网络框架
客户端
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class mManagerSocket :Singleton<mManagerSocket>
{
// 消息队列中的元素类型
class MsgItem
{
//消息类型
public int msgid;
public byte[] msg;
}
// 代参数的委托类
public delegate void OnMessage_CenterFunce( byte[] msg);
// 每一个客户端给服务器的消息ID对应一个委托类,放入字典管理起来
public Dictionary<int, OnMessage_CenterFunce> dic = new Dictionary<int, OnMessage_CenterFunce>();
// 消息队列,用于存储从服务器接受来的包,便于主线程获取处理
private Queue<MsgItem> all_Msgitem = new Queue<MsgItem>();
// 注册消息处理回调
public void OnResour_Funces(int msgid, OnMessage_CenterFunce resFunces)
{
//定义一个准备接受从那个字典类去除来的属性
OnMessage_CenterFunce funce = null;
//判断根据消息类型拿出对应的委托类
if (dic.TryGetValue(msgid, out funce))
{
//注册消息回调函数
funce += resFunces;
}
else
{
//如果没有加入到字典管理起来
dic.Add(msgid, resFunces);
}
}
/// <summary>
/// 对队里中的数据进行发布
/// </summary>
/// <param name="msgid"></param>
/// <param name="clientid"></param>
/// <param name="msg"></param>
public void OnMessagehandling(int msgid,byte[] msg)
{
//根据从队列去处的消息类型拿到集合内对应的事件类
OnMessage_CenterFunce funce = null;
//判断根据消息类型拿出对应的委托类
if (dic.TryGetValue(msgid, out funce))
{
//事件发布
funce(msg);
}
}
// 把收到的消息压入队列
public void All_Enqueue(int msgid, byte[] msg)
{
//建立一个元素对象
MsgItem item = new MsgItem();
//同上(消息类型)
item.msgid = msgid;
//把传入进来的具体消息复制到队列类中
item.msg = msg;
//防止多个客户端连接进来
lock (all_Msgitem)
{
//把消息压入队列
all_Msgitem.Enqueue(item);
}
}
// 处理该客户端消息队列中的消息
public void Dele_Dequeue()
{
//一次性处理完所有的积累消息
while (true)
{
//如果消息处里完毕了,退出
if (all_Msgitem.Count <= 0)
{
return;
}
//处理消息出队
MsgItem item = all_Msgitem.Dequeue();
//调用--- 事件发布
OnMessagehandling(item.msgid,item.msg);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System;
using System.IO;
public class NetClicent : Singleton<NetClicent>
{
// 异步通讯所用的附带数据类型
class AscyData
{
// 消息ID
public int mesid;
// 当前写入位置
public int pos;
// 缓冲区
public byte[] buff;
}
// 消息ID长度
public const int MSG_ID_SIZE = sizeof(int);
// 包头长度
public const int HONE_SIZE = sizeof(ushort);
public Socket mServerSocket;
public void StartServer(string mIP, int mPort)
{
mServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint IPE = new IPEndPoint(IPAddress.Parse(mIP), mPort);
try
{
mServerSocket.Connect(IPE);
}
catch (System.Exception)
{
Debug.Log("连接失败");
throw;
}
Debug.Log("连接服务端成功。。。");
Start_Subpackage();
}
//异步读取包处
private void Start_Subpackage()
{
//异步读取所有用到的属性,读取从包头加消息类型开始
AscyData data = new AscyData()
{
buff = new byte[HONE_SIZE + MSG_ID_SIZE],
};
mServerSocket.BeginReceive(data.buff, 0, data.buff.Length, SocketFlags.None, BeginHone, data);
}
private void BeginHone(IAsyncResult ar)
{
//拿到发送过来的长度
int len = mServerSocket.EndReceive(ar);
//从系统中取出之前传入的参数
AscyData data = ar.AsyncState as AscyData;
//判断包的长度和MSGID是否都接受成功
if (len + data.pos == data.buff.Length)
{
//从接受完的字节数组中取出总长度 0代表从0开始全部转换完毕
ushort paselen = BitConverter.ToUInt16(data.buff, 0);
//从接受完的字节数组中取出消息的ID类型 2代表从0开始只转换两个字节
int mesid = BitConverter.ToInt32(data.buff, HONE_SIZE);
//开启一个异步读取包体的对象存储的位置
AscyData da = new AscyData()
{
buff = new byte[paselen - MSG_ID_SIZE],
mesid = mesid,
};
mServerSocket.BeginReceive(da.buff, 0, da.buff.Length, SocketFlags.None, BeginBody, da);
}
else
{
//没有读取完则继续读取包头的剩余部分
data.pos += len;
//异步开始读取包体
mServerSocket.BeginReceive(data.buff, data.pos, data.buff.Length - data.pos, SocketFlags.None, BeginHone, data);
}
}
private void BeginBody(IAsyncResult ar)
{
//同上 --他们所拿到的数据和长度都是真实的数据
int len = mServerSocket.EndReceive(ar);
//获取之前开启存储数据的类的对象
AscyData data = ar.AsyncState as AscyData;
//判断是否读取完毕,读取完毕就放入队列
if (len + data.pos == data.buff.Length)
{
mManagerSocket.Instance .All_Enqueue(data.mesid,data.buff);
//开启读取下一个包
Start_Subpackage();//再次进行回调
}
else
{
//把么有读取完的数据增加到有效数据的末尾
data.pos += len;
mServerSocket.BeginReceive(data.buff, data.pos, data.buff.Length - data.pos, SocketFlags.None, BeginHone, data);
}
}
//服务返回给客户端发送消息
public void Send(int msgid, byte[] msg)
{
//这个要倒IO包 他相当于一个记忆 短暂记忆的一个流 全部拿到发出去
using (MemoryStream mm = new MemoryStream())
{
//拿到你要发送的总长度
ushort length = (ushort)(msg.Length + MSG_ID_SIZE);
//通过IO流的方式连接到MemoryStream
BinaryWriter bw = new BinaryWriter(mm);
//包头放置数据长度,2个字节
bw.Write(length);
//消息类型
bw.Write(msgid);
//具体数据
bw.Write(msg);
//两种写法 这种是全部发送 也没问题
// mServerSocket.Send(mm.GetBuffer());
//返回给客户端消息处,参数一全部的数据包,参数二发送的长度(要加上包头的长度)
mServerSocket.Send(mm.GetBuffer(), length + HONE_SIZE, SocketFlags.None);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Google.Protobuf;
using MyUser;
//意思是 S——服务端 2——TO C --客户端
public enum S2C
{
TankLoginResult = 0,
Generate_playerlist = 1,
Anaphase_Player = 2,
WantMove = 3,
}
/// <summary>
/// 所有客户端给服务器的消息id类型
/// </summary>
//客户端发送给服务端
public enum C2S
{
TankLoginResult = 0,
Generate_playerlist = 1,
Anaphase_Player = 2,
WantMove = 3,
}