unity3d的网络套接字SOCKET模块使用
使用方法简单:
1、新建一个空物体把NetWork挂载上,2、填上ip和prot,3、调用Connet方法;
/* UNITY3D 网络组件,它是单例模式。 通过Network开启和关闭网络; 消息订阅器MsgEvent管理服务端发来的消息 */ 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 { ////// 网络消息广播,当服务端有消息发来是通过它广播 ///public static readonly EventDispatchMsgEvent = new EventDispatch(); public static bool IsConnet { get; private set; } public static bool IsActive { get; private set; } ////// 网络组件实例 ///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("网络错误:" + 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封装了一个轻量通信协议,以8个字节为头部(整型):无符号4字节长度(包括头部8字节)、消息类型无符号2字节、预留无符号2字节。 使用异步方法兼容hololens的uwp平台。消息类型自定义,协议的数据包格式在注释有说。 */
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, ////// 请求连接服务器时发生错误 ///CONNET_IOERROT, ////// 连接中断 ///CONNET_ERROT, ////// 收到消息 ///CONNET_MSG } public class SocketTcp : EventDispatch{ ////// 头部字节 ///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; ////// 允许单个数据包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);//设置回调方法 connetedSaea.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ip), port); //设置远端连接节点,一般用于接收消息 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);//设置回调方法 //codeMsg.Enqueue(1); //连接后开始从服务器读取网络消息 socket.ReceiveAsync(ReceiveSaea); } int fragmentLen; byte[] fragment; ////// 回调读取网络数据、检查是否断线。 /////////private void ReceiveCall(object sender, SocketAsyncEventArgs e) { fragmentLen = e.BytesTransferred;//调用这个函数来结束本次接收并返回接收到的数据长度。 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);//这个函数用来关闭客户端连接 _activity = false; socketState = true; Debug.Log("中断,关闭连接"); 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(); //后关闭服务器 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网络通信 - NetWork组件使用 2019/5/28