Unity中的网络框架
此框架使主要负责客户端和服务端的连接以及数据交换具体实现逻辑根据实际项目进行编写,注册到委托中即可
/// <summary>
/// 通用socket端
/// </summary>
public class SocketObject
{
public Socket socket;//套接字
public byte[] recvBuf;//接收缓冲区
public byte[] sendBuf;//发送缓冲区
public Queue<NetMsgObj> recvQueue;//接收队列
public Queue<NetMsgObj> sendQueue;//发送队列
public IPEndPoint point;//终端
public string IP;//IP
public short Port;//端口
public static SocketObject Regist(string ip,short port)
{
SocketObject temp = new SocketObject();
temp.IP = ip;
temp.Port = port;
temp.point = new IPEndPoint(IPAddress.Parse(ip),port);
temp.socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
temp.recvBuf = new byte[4096];
temp.sendBuf = new byte[4096];
temp.recvQueue = new Queue<NetMsgObj>();
temp.sendQueue = new Queue<NetMsgObj>();
return temp;
}
/// <summary>
/// 设置Socket
/// </summary>
/// <param name="s"></param>
public void SetSocket(Socket s)
{
socket = s;
}
/// <summary>
/// 进入接收队列方法
/// </summary>
/// <param name="nmo"></param>
public void EnRecvQueue(NetMsgObj nmo)
{
recvQueue.Enqueue(nmo);
}
/// <summary>
/// 进入发送队列方法
/// </summary>
/// <param name="nmo"></param>
public void EnSendQueue(NetMsgObj nmo)
{
sendQueue.Enqueue(nmo);
}
}
/// <summary>
/// 消息传递类(协议)此协议根据实际需求进行更改,此处只做示范
/// </summary>
public class NetMsgObj
{
public int len;//长度
public MsgCode code;
public byte[] data;
/// <summary>
/// 获取消息号
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static MsgCode GetCode(byte[] data)
{
byte[] temp = new byte[2];
temp[0] = data[4];
temp[1] = data[5];
return (MsgCode)BitConverter.ToInt16(temp,0);
}
/// <summary>
/// 序列化
/// </summary>
/// <param name="head"></param>
/// <param name="body"></param>
/// <returns></returns>
public static byte[] Package(MsgCode code,byte[] body)
{
byte[] temp = new byte[6 + body.Length];
byte[] bs = BitConverter.GetBytes((short)code);
byte[] length = BitConverter.GetBytes(temp.Length);
Array.Copy(length, 0, temp, 0, 4);
Array.Copy(bs,0,temp,4,2);
Array.Copy(body,0,temp,6,body.Length);
return temp;
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static NetMsgObj GetNMO(byte[] data)
{
NetMsgObj temp = new NetMsgObj();
temp.len = GetHead(data);
temp.code = GetCode(data);
byte[] body = new byte[data.Length - 6];
Array.Copy(data, 6, body, 0, body.Length);
temp.data = body;
return temp;
}
/// <summary>
/// 打包数据
/// </summary>
/// <returns></returns>
public byte[] Package()
{
byte[] temp = new byte[6 + data.Length];
byte[] length = BitConverter.GetBytes(temp.Length);
byte[] codes = BitConverter.GetBytes((short)code);
Array.Copy(length, 0, temp, 0, 4);
Array.Copy(codes, 0, temp, 4, 2);
Array.Copy(data, 0, temp, 6, data.Length);
return temp;
}
/// <summary>
/// 获取头(长度)
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static int GetHead(byte[] data)
{
byte[] head = new byte[4];
for (int i = 0; i < 4; i++)
{
head[i] = data[i];
}
return BitConverter.ToInt32(head,0);
}
}
public delegate void Handle(NetMsgObj nmo);
//客户端类 此类可以在服务器承载连接上的客户端,也可以直接当做客户端使用
public class Client
{
public string clientID;
public event Handle Handler;
public int content;//剩余容量
public int read = 0;//已用容量
public SocketObject socketObject;
public void AddListener(Handle h)
{
Handler += h;
}
/// <summary>
/// 初始化客户端
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
public void Init(string ip = "127.0.0.1", short port = 4396)
{
socketObject = SocketObject.Regist(ip, port);
content = socketObject.recvBuf.Length;
}
/// <summary>
/// 连接服务器
/// </summary>
public void ConnectServer()
{
socketObject.socket.BeginConnect(socketObject.point, AsyncConnectCallBack, socketObject);
}
/// <summary>
/// 连接回调
/// </summary>
/// <param name="ar"></param>
private void AsyncConnectCallBack(IAsyncResult ar)
{
SocketObject so = (SocketObject)ar.AsyncState;
so.socket.EndConnect(ar);
Debug.Log("连接成功");
if (so.socket.Connected)
so.socket.BeginReceive(so.recvBuf, 0, so.recvBuf.Length, SocketFlags.None, AsyncRecvCallBack, so);
}
/// <summary>
/// 服务器调用接收
/// </summary>
public void RecvProcess()
{
if (socketObject.socket.Connected)
socketObject.socket.BeginReceive(socketObject.recvBuf, read, content, SocketFlags.None, AsyncRecvCallBack, socketObject);
}
/// <summary>
/// 接收回调
/// </summary>
/// <param name="ar"></param>
private void AsyncRecvCallBack(IAsyncResult ar)
{
SocketObject so = (SocketObject)ar.AsyncState;
int len = so.socket.EndReceive(ar);
read = len;
while (true)
{
if (read < 6)
break;
int plen = BitConverter.ToInt32(socketObject.recvBuf,0);
if (read < plen)
break;
byte[] temp = new byte[plen];
Array.Copy(socketObject.recvBuf,0,temp,0,plen);
NetMsgObj nmo = NetMsgObj.GetNMO(temp);
socketObject.recvQueue.Enqueue(nmo);
Array.Copy(socketObject.recvBuf,plen,socketObject.recvBuf,0,read-plen);
read -= plen;
content = so.recvBuf.Length - read;
}
if (so.socket.Connected)
so.socket.BeginReceive(so.recvBuf, read, content, SocketFlags.None, AsyncRecvCallBack, so);
}
/// <summary>
/// 真实接收
/// </summary>
public void UpdateRecvMsg()
{
while (socketObject.recvQueue.Count > 0)
{
NetMsgObj temp = socketObject.recvQueue.Dequeue();
Handler?.Invoke(temp);
}
}
/// <summary>
/// 真实发送
/// </summary>
public void UpdateSendMsg()
{
while (socketObject.sendQueue.Count > 0)
{
NetMsgObj temp = socketObject.sendQueue.Dequeue();
byte[] data = temp.Package();
socketObject.socket.BeginSend(data, 0, data.Length, SocketFlags.None, AsyncSendCallBack, socketObject);
}
}
/// <summary>
/// 发送回调
/// </summary>
/// <param name="ar"></param>
private void AsyncSendCallBack(IAsyncResult ar)
{
SocketObject so = (SocketObject)ar.AsyncState;
int len = so.socket.EndSend(ar);
if (len > 0)
{
Debug.Log("发送成功");
}
}
/// <summary>
/// 虚假发送
/// </summary>
/// <param name="code"></param>
/// <param name="data"></param>
public void SendMsg(MsgCode code, byte[] data)
{
NetMsgObj temp = new NetMsgObj();
temp.code = code;
temp.data = data;
temp.len = 6 + data.Length;
socketObject.EnSendQueue(temp);
}
public byte[] Zhanbao()
{
byte[] sum = new byte[0];
if (socketObject.recvQueue.Count > 0)
{
while (socketObject.recvQueue.Count > 0)
{
NetMsgObj nmo = socketObject.recvQueue.Dequeue();
sum = Append(sum, NetMsgObj.Package(nmo.code, nmo.data));
}
}
else
{
Location l = new Location();
l.clientID = clientID;
l.x = 0;
l.z = 0;
string str = JsonUtility.ToJson(l);
byte[] data = NetMsgObj.Package(MsgCode.MOVE, Encoding.UTF8.GetBytes(str));
sum = Append(sum, data);
}
return sum;
}
public byte[] Append(byte[] src, byte[] data)
{
byte[] temp = new byte[src.Length + data.Length];
Array.Copy(src, 0, temp, 0, src.Length);
Array.Copy(data, 0, temp, src.Length, data.Length);
return temp;
}
/// <summary>
/// 服务器调用发送
/// </summary>
public void SendProcess(byte[] data)
{
socketObject.socket.BeginSend(data, 0, data.Length, SocketFlags.None, AsyncSendCallBack, socketObject);
}
}
//这是处理的消息类型枚举,根据需求添加
public enum MsgCode
{
OPEN,
CLOSE,
CLOSEALL,
LOGIN,
MOVE,
OTHER,
HEART,
PONG,
}
//服务器类,此类负责服务器的数据接收,以及接收连接上的客户端
public class Server
{
static int index = 1000;
SocketObject socketObject;
public List<Client> users = new List<Client>();
Dictionary<string, Client> usersID = new Dictionary<string, Client>();//userID字典
public void Init(string ip = "127.0.0.1", short port = 4396)
{
socketObject = SocketObject.Regist(ip, port);
}
/// <summary>
/// 开启服务器
/// </summary>
public void StartServer(int number = 20)
{
socketObject.socket.Bind(socketObject.point);
socketObject.socket.Listen(number);
socketObject.socket.BeginAccept(AsyncAcceptCallBack, socketObject);
}
/// <summary>
/// 接受回调
/// </summary>
/// <param name="ar"></param>
private void AsyncAcceptCallBack(IAsyncResult ar)
{
SocketObject so = (SocketObject)ar.AsyncState;
Socket s = so.socket.EndAccept(ar);
Client c = new Client();
c.Init();
c.socketObject.SetSocket(s);
string id = "Player" + index++;
byte[] data = NetMsgObj.Package(MsgCode.LOGIN, Encoding.UTF8.GetBytes(id));
byte[] data2 = NetMsgObj.Package(MsgCode.OTHER, Encoding.UTF8.GetBytes(id));
foreach (var item in users)
{
item.SendProcess(data2);
}
users.Add(c);
usersID.Add(id, c);
c.SendProcess(data);
foreach (var item in usersID.Keys)
{
byte[] data3 = NetMsgObj.Package(MsgCode.OTHER, Encoding.UTF8.GetBytes(item));
c.SendProcess(data3);
}
c.RecvProcess();
socketObject.socket.BeginAccept(AsyncAcceptCallBack, socketObject);
}
public void UpdateRecv()
{
if (users.Count > 0)
{
foreach (var item in users)
{
item.UpdateRecvMsg();
}
}
}
public void UpdateSend()
{
if (users.Count > 0)
{
foreach (var item in users)
{
item.UpdateSendMsg();
}
}
}
}