`````````````````````````````````protobuf`````````````````````````````
package cs; message CSLoginInfo { required string UserName = 1;//账号 required string Password = 2;//密码 } //发送登录请求 message CSLoginReq { required CSLoginInfo LoginInfo = 1; } //登录请求回包数据 message CSLoginRes { required uint32 result_code = 1; }
package cs; enum EnmCmdID { CS_LOGIN_REQ = 10001;//登录请求协议号 CS_LOGIN_RES = 10002;//登录请求回包协议号 }
文件格式.proto
然后用protogen.exe 使用提示命令进行编译。会得到两个.cs文件。 注意看里面可以发现usingnamespace cs
`````````````````````````````````````````更改Client与Server的消息传输``````````````````````````````
Client:(U3D)
挂载摄像机上:
using System.Collections; using System.Collections.Generic; using UnityEngine; using cs; using TcpClinet; public class testProto : MonoBehaviour { // Use this for initialization void Start () { MyClient.Connect("192.168.200.1",88); CSLoginInfo mLoginInfo = new CSLoginInfo(); mLoginInfo.UserName = "ycb"; mLoginInfo.Password = "1234565"; CSLoginReq mReq = new CSLoginReq(); mReq.LoginInfo = mLoginInfo; MyClient.Send((int)EnmCmdID.CS_LOGIN_REQ, mReq); } }
Client主体逻辑部分
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Net; using System.Net.Sockets; using UnityEngine; using ProtoBuf; using cs; namespace TcpClinet { class MyClient { static byte[] data = new byte[1024]; public static Socket socketClient; static Message msg = new Message(); public static void Connect(string ip,int port) { socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketClient.Connect(new IPEndPoint(IPAddress.Parse(ip), port)); socketClient.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveCallBack, socketClient); } static void ReceiveCallBack(IAsyncResult ar) { // ar.AsyncState 可以获得之前传递的object Socket socketClient = null; try { socketClient = ar.AsyncState as Socket; int count = socketClient.EndReceive(ar); if (count == 0) { //即便是空数据也不会是0,客户端不会发送空数据, 只有在结束时才有0的可能性 socketClient.Close(); return; } msg.AddCount(count); msg.ReadProtoMessage(); socketClient.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveCallBack, socketClient); } catch (Exception e) { Console.WriteLine(e); if (socketClient != null) { socketClient.Close(); } } } //protobuf public static void Send(int typeId,IExtensible msgStr) { byte[] typeBytes = BitConverter.GetBytes(typeId); byte[] dataBytes = PackCodec.Serialize(msgStr); int msgLen = typeBytes.Length + dataBytes.Length; byte[] lengthBytes = BitConverter.GetBytes(msgLen); byte[] newBytes = lengthBytes.Concat(typeBytes).ToArray().Concat(dataBytes).ToArray(); socketClient.Send(newBytes); //总长度(int32) + typeid(int32) + 报文 } //非protobuf public static void Send(string msgStr) { int count = socketClient.Receive(msg.Data); byte[] dataBytes = Encoding.UTF8.GetBytes(msgStr); int msgLen = msgStr.Length; byte[] lengthBytes = BitConverter.GetBytes(msgLen); byte[] newBytes = lengthBytes.Concat(dataBytes).ToArray(); socketClient.Send(newBytes); } public static void Close() { socketClient.Close(); } } }
Message报文部分:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using UnityEngine; using ProtoBuf; using cs; namespace TcpClinet { class Message { private byte[] data = new byte[1024]; private int startIndex = 0; public byte[] Data { get { return data; } } public int StartIndex { get { return startIndex; } } public int RemainSize { get { return data.Length - startIndex; } } public void AddCount(int count) { startIndex += count; } /// <summary> /// 解析数据 /// </summary> public void ReadMessage() { while (true) { if (startIndex <= 4) { return; } int count = BitConverter.ToInt32(data, 0); if ((startIndex - 4) >= count) { string s = System.Text.Encoding.UTF8.GetString(data, 4, count); Array.Copy(data, count + 4, data, 0, startIndex - 4 - count); startIndex -= count + 4; //Debug.Log(count+" "+s); } else break; } } public void ReadProtoMessage() { while (true) { if (startIndex <= 4) return; int count = BitConverter.ToInt32(data, 0); if ((startIndex - 4) >= count) { int typeId = BitConverter.ToInt32(data, 4); if (typeId == (int)EnmCmdID.CS_LOGIN_RES) { byte[] msg = new byte[count - 4]; Array.Copy(data, 8, msg, 0, count - 4); CSLoginRes ServerRes = PackCodec.Deserialize<CSLoginRes>(msg); UInt32 res = ServerRes.result_code; Debug.Log("数据内容:res =" + res); Array.Copy(data, count + 4, data, 0, startIndex - 4 - count); startIndex -= count + 4; } } } } } }
解码部分:
using UnityEngine; using System.Collections; using System.IO; using System; using ProtoBuf; /// <summary> /// 网络协议数据打包和解包类 /// </summary> public class PackCodec { /// <summary> /// 序列化 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="msg"></param> /// <returns></returns> [[ static public byte[] Serialize<T>(T msg) { byte[] result = null; if (msg != null) { using (var stream = new MemoryStream()) { Serializer.Serialize<T>(stream, msg); result = stream.ToArray(); } } return result; } /// <summary> /// 反序列化 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="message"></param> /// <returns></returns> static public T Deserialize<T>(byte[] message) { T result = default(T); if (message != null) { using (var stream = new MemoryStream(message)) { result = Serializer.Deserialize<T>(stream); } } return result; } }
服务器:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Sockets; using System.Net; using ProtoBuf; using cs; namespace TcpServer { class Program { static Socket socketServer; static byte[] dataBuffer = new byte[1024]; static void Main(string[] args) { StartServerAsync(); Console.ReadKey(); } static void StartServerAsync() { socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress iPAddress = IPAddress.Parse("192.168.200.1"); IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 88); socketServer.Bind(iPEndPoint); socketServer.Listen(10); //Socket clientSocket = socketServer.Accept(); 下面支持多个客户端,改为异步, 之前c++服务器用的epoll这里似乎不需要关注 socketServer.BeginAccept(AcceptCallBack, socketServer); } static Message msg = new Message(); static void AcceptCallBack(IAsyncResult ar) { Socket socketServer = ar.AsyncState as Socket; Socket socketClient = socketServer.EndAccept(ar); CSLoginRes res = new CSLoginRes(); res.result_code = 0; Send(socketClient, (int)EnmCmdID.CS_LOGIN_RES, res); socketClient.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveCallBack, socketClient); socketServer.BeginAccept(AcceptCallBack, socketServer); } static void SendMessage(Socket socketClient,string msgStr) { byte[] dataBytes = Encoding.UTF8.GetBytes(msgStr); int msgLen = msgStr.Length; byte[] lengthBytes = BitConverter.GetBytes(msgLen); byte[] newBytes = lengthBytes.Concat(dataBytes).ToArray(); socketClient.Send(newBytes); } //protobuf public static void Send(Socket socketClient,int typeId, IExtensible msgStr) { byte[] typeBytes = BitConverter.GetBytes(typeId); byte[] dataBytes = PackCodec.Serialize(msgStr); int msgLen = typeBytes.Length + dataBytes.Length; byte[] lengthBytes = BitConverter.GetBytes(msgLen); byte[] newBytes = lengthBytes.Concat(typeBytes).ToArray().Concat(dataBytes).ToArray(); socketClient.Send(newBytes); //总长度(int32) + typeid(int32) + 报文 } static void ReceiveCallBack(IAsyncResult ar) { // ar.AsyncState 可以获得之前传递的object Socket socketClient = null; try { socketClient = ar.AsyncState as Socket; int count = socketClient.EndReceive(ar); if (count == 0) { //即便是空数据也不会是0,客户端不会发送空数据, 只有在结束时才有0的可能性 socketClient.Close(); return; } msg.AddCount(count); msg.ReadProtoMessage(); socketClient.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveCallBack, socketClient); } catch (Exception e) { Console.WriteLine(e); if (socketClient != null) { socketClient.Close(); } } } } }
Message:与上面不同
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using cs; namespace TcpServer { class Message { private byte[] data = new byte[1024]; private int startIndex = 0; public byte[] Data { get { return data; } } public int StartIndex { get { return startIndex; } } public int RemainSize { get { return data.Length - startIndex; } } public void AddCount(int count) { startIndex += count; } /// <summary> /// 解析数据 /// </summary> public void ReadMessage() { while (true) { if (startIndex <= 4) { return; } int count = BitConverter.ToInt32(data, 0); if ((startIndex - 4) >= count) { string s = System.Text.Encoding.UTF8.GetString(data, 4, count); Array.Copy(data, count + 4, data, 0, startIndex - 4 - count); startIndex -= count + 4; Console.WriteLine(count ); } else break; } } public void ReadProtoMessage() { while (true) { if (startIndex <= 4) return; int count = BitConverter.ToInt32(data, 0); if((startIndex-4)>=count ) { int typeId = BitConverter.ToInt32(data, 4); if (typeId == (int)EnmCmdID.CS_LOGIN_REQ) { byte[] msg = new byte[count-4]; Array.Copy(data, 8, msg, 0, count-4); CSLoginReq clientReq = PackCodec.Deserialize<CSLoginReq>(msg); string user_name = clientReq.LoginInfo.UserName; string pass_word = clientReq.LoginInfo.Password; Console.WriteLine("数据内容:UserName={0},Password={1}", user_name, pass_word); Array.Copy(data, count + 4, data, 0, startIndex - 4 - count); startIndex -= count + 4; } } } } } }
ProtoBuf的解码部分 同上面,并且生成的.cs文件也需要扔进来,还需要引入protobuf-net.dll
using System.Collections; using System.IO; using System; using ProtoBuf; /// <summary> /// 网络协议数据打包和解包类 /// </summary> public class PackCodec { /// <summary> /// 序列化 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="msg"></param> /// <returns></returns> [[ static public byte[] Serialize<T>(T msg) { byte[] result = null; if (msg != null) { using (var stream = new MemoryStream()) { Serializer.Serialize<T>(stream, msg); result = stream.ToArray(); } } return result; } /// <summary> /// 反序列化 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="message"></param> /// <returns></returns> static public T Deserialize<T>(byte[] message) { T result = default(T); if (message != null) { using (var stream = new MemoryStream(message)) { result = Serializer.Deserialize<T>(stream); } } return result; } }