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