unity3d的網絡套接字SOCKET模塊使用
2019/6/12 點擊:
使用方法簡單:
1、新建一個空物體把NetWork掛載上,2、填上ip和prot,3、調用(yòng)Connet方法(fǎ);
/*
UNITY3D 網(wǎng)絡組件,它是單例模式。
通(tōng)過Network開啟和關閉網絡;
消息訂閱器MsgEvent管理服務端(duān)發來的(de)消息
*/
using UnityEngine;
using Assets.Scripts.Events;
using Assets.Scripts.Util;
using Assets.Scripts.Net;
using System;public enum NetMsgType
{
////// 新消息
///newMsg = -4,
////// 連接服務中斷(duàn)
///interrupt = -3,
////// 請求錯誤
///error = -2,
////// 連接(jiē)成功
///complete = -1,
////// 服務端(duān)握手響應
///state = 1
}
public class Network : MonoBehaviour
{
////// 網絡消息廣播,當(dāng)服務端(duān)有消息發來是通過它廣播
///public static readonly EventDispatchMsgEvent = new EventDispatch();
public static bool IsConnet { get; private set; }
public static bool IsActive { get; private set; }
////// 網絡組件實例(lì)
///public static Network Server { get; private set; } private SocketTcp socket;
public string ip = "";
public int prot;
void Awake()
{
Server = this;
}
void Start()
{
}
////// 向服務端發送數據
//////協議接口類型///預留///要發送的數據public void outCall(ushort type, ushort error, ByteArray data)
{
if (IsConnet)
{
socket.Send(type, error, data);
}
}
public void Connet()
{
if (IsActive == false)
{
IsActive = true;
socket = new SocketTcp(ip, prot);
socket.AddListener(NetEvent.CONNETED, Conneted);
socket.AddListener(NetEvent.CONNET_IOERROT, ConnetIOError);
socket.AddListener(NetEvent.CONNET_ERROT, ConnetError);
socket.AddListener(NetEvent.CONNET_MSG, MsgHandler); socket.Start();
}
}
private void Conneted(EventData data)
{
IsConnet = true;
MsgEvent.Dispatch(NetMsgType.complete);
}
void ConnetIOError(EventData data)
{
IsConnet = false;
IsActive = false;
MsgEvent.Dispatch(NetMsgType.error);
}
void ConnetError(EventData data)
{
IsConnet = false;
IsActive = false;
MsgEvent.Dispatch(NetMsgType.interrupt);
}
void MsgHandler(EventData data)
{
BucketItem msg = (BucketItem)data.data;
msg.ByteArray.Position = 0;
if (msg.Error > 0)
{
Debug.Log("網絡錯(cuò)誤(wù):" + msg.Error);
return;
}
if (Enum.IsDefined(typeof(NetMsgType), msg.Type))
{
MsgEvent.Dispatch((NetMsgType)msg.Type, msg);
}
else
{
Debug.Log("未定義網絡消息:" + msg.Type);
}
}
public void Disconnect()
{
IsConnet = false;
IsActive = false;
socket.RemoveListener(NetEvent.CONNETED, Conneted);
socket.RemoveListener(NetEvent.CONNET_IOERROT, ConnetIOError);
socket.RemoveListener(NetEvent.CONNET_ERROT, ConnetError);
socket.RemoveListener(NetEvent.CONNET_MSG, MsgHandler);
socket.Destroy();
socket = null;
}
void FixedUpdate()
{ }
void Update()
{
if (socket != null) socket.Updata();
}
//程序退出則關閉(bì)連接(jiē)
void OnApplicationQuit()
{
if (socket != null) socket.Destroy();
}
}
/*
socketTcp封裝了一個輕(qīng)量通(tōng)信協議,以8個字節為頭部(整型):無符號4字節長(zhǎng)度(包括頭部8字節)、消息類型無符號2字節、預留無符號2字節。
使用異步方法兼容(róng)hololens的uwp平台。消息類型自定義,協(xié)議的數據包格(gé)式在注釋有說。 */
using Assets.Scripts.Events;
using System;
using System.Collections;
using Assets.Scripts.Util;
using UnityEngine;
using System.Collections.Generic;
#if !UWP
using System.Net;
using System.Net.Sockets;
#else
using Windows.Networking.Sockets;
using Windows.Networking.Connectivity;
using Windows.Networking;
#endif
namespace Assets.Scripts.Net
{
public enum NetEvent{
////// 連接建立
///CONNETED,
////// 請求連(lián)接服務器時發生錯誤
///CONNET_IOERROT,
////// 連(lián)接中斷
///CONNET_ERROT,
////// 收到消(xiāo)息
///CONNET_MSG
}
public class SocketTcp : EventDispatch{
////// 頭部字節
///public const int head_size = 8;
////// 是否使用小端
///public const bool IsLittleEndian = true;
bool _activity = false;
////// 是否已(yǐ)啟用
///public bool Activity
{
get { return _activity; }
}
////// 接受的消息(xī),隊列
///private QueueMsgList;
private QueuecodeMsg;
public int port { get; private set; }
public string ip { get; private set; }
Socket socket;
SocketAsyncEventArgs ReceiveSaea;
SocketAsyncEventArgs sendSaea;
byte[] sendData;
////// 允許單個數據包30720字節
///
///const int RECV_LEN = 30720;
byte[] recv_buf = new byte[RECV_LEN];
Bucket bucket;
bool socketState=false;
public SocketTcp(string ip, int port)
{
this.port = port;
this.ip = ip;
bucket = new Bucket();
codeMsg = new Queue();
MsgList = new Queue();
}
private SocketAsyncEventArgs connetedSaea;
////// 發起鏈接請(qǐng)求(qiú)
/// 會調度CONNETED或CONNET_IOERROT事件
///public void Start()
{
if (socket==null)
{
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
connetedSaea = new SocketAsyncEventArgs();
connetedSaea.Completed += new EventHandler(connetedCall);//設置回調方(fāng)法
connetedSaea.RemoteEndPoint = new IPEndPoint(ipadsdress.Parse(ip), port); //設置遠端連接節點,一般用(yòng)於接收消(xiāo)息
sendSaea = new SocketAsyncEventArgs();
//連接到服務器
socket.ConnectAsync(connetedSaea);
}
catch (Exception e)
{
Debug.Log(e);
Dispatch(NetEvent.CONNET_IOERROT);
}
}
}
private void connetedCall(object sender, SocketAsyncEventArgs e)
{
_activity = true;
codeMsg.Enqueue(NetEvent.CONNETED);
ReceiveSaea = new SocketAsyncEventArgs();
ReceiveSaea.SetBuffer(recv_buf, 0, recv_buf.Length);//設置緩衝區
ReceiveSaea.Completed += new EventHandler(ReceiveCall);//設置回(huí)調(diào)方法
//codeMsg.Enqueue(1);
//連接後開始從服務(wù)器(qì)讀取網絡消息
socket.ReceiveAsync(ReceiveSaea);
}
int fragmentLen;
byte[] fragment;
////// 回調讀取網絡數(shù)據、檢查是否斷線。
/////////private void ReceiveCall(object sender, SocketAsyncEventArgs e)
{
fragmentLen = e.BytesTransferred;//調用這個函數來結束本次接(jiē)收並返回接收到的數據(jù)長(zhǎng)度。
if (fragmentLen > 0)
{
fragment = new byte[fragmentLen];
Array.Copy(recv_buf, 0, fragment, 0, fragmentLen);
Queuearr = bucket.Infuse(fragment);
while (arr.Count > 0)
{
MsgList.Enqueue(arr.Dequeue());
}
socket.ReceiveAsync(ReceiveSaea);
}
else
{
ReceiveSaea.Dispose();
bucket.Reset();
socket.Shutdown(SocketShutdown.Receive);//這個函數用來關閉客戶端連(lián)接
_activity = false;
socketState = true;
Debug.Log("中(zhōng)斷,關閉連接");
return;
}
}
////// 發送字節流
//////public void Send(ushort type, ushort error, ByteArray data)
{
uint len = (uint)data.Length + head_size;
//清空發送緩存
sendData = new byte[len];
ByteHelp.WriteNumber(len, ref sendData, 0, IsLittleEndian);
ByteHelp.WriteNumber(type, ref sendData, 4, IsLittleEndian);
ByteHelp.WriteNumber(error, ref sendData, 6, IsLittleEndian);
if (data.Length > 0)
{
Array.Copy(data.Data, 0, sendData, head_size, data.Length);
}
//sendData.
//數據類型轉換
//sendData = Encoding.ASCII.GetBytes(sendStr);
//發送
sendSaea.SetBuffer(sendData, 0, sendData.Length);
socket.SendAsync(sendSaea);
}
////// 主線程每幀調用以拿取數據
///public void Updata()
{
while (codeMsg.Count > 0)
{
Dispatch(codeMsg.Dequeue());
}
while (MsgList.Count > 0)
{
Dispatch(NetEvent.CONNET_MSG, MsgList.Dequeue());
}
if (socketState)
{
//Debug.Log("連接丟失,是否要重連");
socketState = false;
Dispatch(NetEvent.CONNET_ERROT);
}
}
public void Destroy()
{
base.Dispose();
//後關閉服(fú)務器
if (socket != null && socket.Connected)
{
//this.socket.Disconnect(true);
//this.socket.Shutdown(SocketShutdown.Both);
//socket.Dispose();
socket.Shutdown(SocketShutdown.Receive);
socket.Shutdown(SocketShutdown.Send);
ReceiveSaea.Dispose();
}
bucket.Reset();
MsgList.Clear();
codeMsg.Clear();
socketState = false;
if (sendSaea != null) connetedSaea = null;
if(sendSaea!=null) sendSaea.Dispose();
sendSaea = null;
if (_activity)
{
_activity = false;
}
}
}
}- 上一篇:UNITY3D使用SHADER給頂點設(shè)置顏色 2019/6/12
- 下一篇:Unity3d網絡通信 - NetWork組件使用 2019/5/28
