unity3d的網(wǎng)絡套接字SOCKET模塊使用
2019/6/12??????點擊:
使用方法簡單:
1、新建一個空物體把NetWork掛載上,2、填上ip和prot,3、調用Connet方法;
/* UNITY3D 網(wǎng)絡組件,它是單例模式。 通過Network開啟和關閉網(wǎng)絡; 消息訂閱器MsgEvent管理服務端發(fā)來的消息 */ using UnityEngine; using Assets.Scripts.Events; using Assets.Scripts.Util; using Assets.Scripts.Net; using System; public enum NetMsgType { ////// 新消息 ///newMsg = -4, ////// 連接服務中斷 ///interrupt = -3, ////// 請求錯誤 ///error = -2, ////// 連接成功 ///complete = -1, ////// 服務端握手響應 ///state = 1 } public class Network : MonoBehaviour { ////// 網(wǎng)絡消息廣播,當服務端有消息發(fā)來是通過它廣播 ///public static readonly EventDispatchMsgEvent = new EventDispatch(); public static bool IsConnet { get; private set; } public static bool IsActive { get; private set; } ////// 網(wǎng)絡組件實例 ///public static Network Server { get; private set; } private SocketTcp socket; public string ip = ""; public int prot; void Awake() { Server = this; } void Start() { } ////// 向服務端發(fā)送數(shù)據(jù) //////協(xié)議接口類型///預留///要發(fā)送的數(shù)據(jù)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("網(wǎng)絡錯誤:" + msg.Error); return; } if (Enum.IsDefined(typeof(NetMsgType), msg.Type)) { MsgEvent.Dispatch((NetMsgType)msg.Type, msg); } else { Debug.Log("未定義網(wǎng)絡消息:" + 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(); } //程序退出則關閉連接 void OnApplicationQuit() { if (socket != null) socket.Destroy(); } } /* socketTcp封裝了一個輕量通信協(xié)議,以8個字節(jié)為頭部(整型):無符號4字節(jié)長度(包括頭部8字節(jié))、消息類型無符號2字節(jié)、預留無符號2字節(jié)。 使用異步方法兼容hololens的uwp平臺。消息類型自定義,協(xié)議的數(shù)據(jù)包格式在注釋有說。 */
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, ////// 請求連接服務器時發(fā)生錯誤 ///CONNET_IOERROT, ////// 連接中斷 ///CONNET_ERROT, ////// 收到消息 ///CONNET_MSG } public class SocketTcp : EventDispatch{ ////// 頭部字節(jié) ///public const int head_size = 8; ////// 是否使用小端 ///public const bool IsLittleEndian = true; bool _activity = false; ////// 是否已啟用 ///public bool Activity { get { return _activity; } } ////// 接受的消息,隊列 ///private QueueMsgList; private QueuecodeMsg; public int port { get; private set; } public string ip { get; private set; } Socket socket; SocketAsyncEventArgs ReceiveSaea; SocketAsyncEventArgs sendSaea; byte[] sendData; ////// 允許單個數(shù)據(jù)包30720字節(jié) /// ///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; ////// 發(fā)起鏈接請求 /// 會調度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);//設置回調方法 connetedSaea.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ip), port); //設置遠端連接節(jié)點,一般用于接收消息 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);//設置緩沖區(qū) ReceiveSaea.Completed += new EventHandler(ReceiveCall);//設置回調方法 //codeMsg.Enqueue(1); //連接后開始從服務器讀取網(wǎng)絡消息 socket.ReceiveAsync(ReceiveSaea); } int fragmentLen; byte[] fragment; ////// 回調讀取網(wǎng)絡數(shù)據(jù)、檢查是否斷線。 /////////private void ReceiveCall(object sender, SocketAsyncEventArgs e) { fragmentLen = e.BytesTransferred;//調用這個函數(shù)來結束本次接收并返回接收到的數(shù)據(jù)長度。 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);//這個函數(shù)用來關閉客戶端連接 _activity = false; socketState = true; Debug.Log("中斷,關閉連接"); return; } } ////// 發(fā)送字節(jié)流 //////public void Send(ushort type, ushort error, ByteArray data) { uint len = (uint)data.Length + head_size; //清空發(fā)送緩存 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. //數(shù)據(jù)類型轉換 //sendData = Encoding.ASCII.GetBytes(sendStr); //發(fā)送 sendSaea.SetBuffer(sendData, 0, sendData.Length); socket.SendAsync(sendSaea); } ////// 主線程每幀調用以拿取數(shù)據(jù) ///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(); //后關閉服務器 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給頂點設置顏色 2019/6/12
- 下一篇:Unity3d網(wǎng)絡通信 - NetWork組件使用 2019/5/28