一个简单 小型的C#Socket网络通信库的制作(服务器客户端互
2019-07-29 本文已影响0人
懒_开果
就一个不用 理解之间的通信代码原理之类的 几句代码快速搭建服务器和客户端
思维导图:
image.png过程大概是KGSocketClient/KGSocketServe 创建了KGNetSession 会话管理进行发送/接收数据的监听会进行一次开启事件 OnStartRecive() 函数回调, 监听到的数据包KGNetPacket 通过KGPackExtension 转化成KGNetData自已定义的数据结构类,然后在KGNetSession里面的 OnReciveData(T) 函数 进行回调
下面直接开始代码解析
1.KGNetData 自定义的数据类
这个好像没啥好说的=。= 自定义的数据类都要继承他
//传输的数据都必须打上可序列化的标签
[Serializable]
public abstract class KGNetData
{
public int Err;
public int Cmd;
}
2.KGNetPacket 消息包的数据类
[图片上传失败...(image-3c0ba8-1564388496437)]
因为每条消息包 你不知道他的长度 所以要在前面利用BitConverter.GetBytes获取一个包的长度Int值
这个int就站byte[]四个长度 所以HeadLength=4,然后获取到长度了在SetPackLen给PacketBuff赋值上获取到的长度
public class KGNetPacket
{
public byte[] PacketBuff;
public int HeadLength = 4;//这里是标头的长度
public int HeadIndex;//这里有时候分包接收到一两个 所以要进行记录已经接收到两个了 还差几个
public int PacketBuffLength ;//数据包的长度
public int PacketIndex;//和上面一样意思
/// <summary>
/// 获取四个字节转成的int长度
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public void SetPackLen()
{
PacketBuffLength = BitConverter.ToInt32(PacketBuff, 0);
PacketBuff =new byte[PacketBuffLength];
}
public void Refresh()
{
PacketBuff = null;
PacketIndex = 0;
HeadIndex = 0;
}
}
3.KGPackExtension 打消息包拓展工具类
/// <summary>
/// 打包消息的拓展工具类
/// </summary>
public static class KGPackExtension
{
#region 打包消息包的
/// <summary>
/// 反序列化消息包返回自定义数据类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
public static T DeSerialization<T>(this byte[] data) where T:KGNetData
{
//using 创建完会自动释放内存 创建流MemoryStream 读消息
using (MemoryStream ms=new MemoryStream(data))
{
//BinaryFormatter 用来反,序列化流的
BinaryFormatter binary = new BinaryFormatter();
//反序列成自定义数据类型
T netdata = (T) binary.Deserialize(ms);
return netdata;
}
}
/// <summary>
/// 把自定义数据类型序列化成byte[] 数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
private static byte[] Serialization<T>(this T data) where T : KGNetData
{
//using 创建完会自动释放内存 创建流MemoryStream
using (MemoryStream ms = new MemoryStream())
{
//BinaryFormatter 用来反,序列化流的
BinaryFormatter binary = new BinaryFormatter();
//把数据写进去流里面
binary.Serialize(ms,data);
//这里是指定流开始的位置
ms.Seek(0, SeekOrigin.Begin);
//转换byte[]返回
return ms.ToArray();
}
}
/// <summary>
/// 为消息包前头增加消息包长度
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] PackNetDataLen(this byte[] data)
{
//获取消息包长度返回一个byte[4] //连接合并数据包 进行最终返回
return BitConverter.GetBytes(data.Length).Concat(data).ToArray();
}
/// <summary>
/// 打包自定义数据类的消息包 加上包长
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] PackNetData<T>(this T data) where T : KGNetData
{
return data.Serialization().PackNetDataLen();
}
#endregion
}
4.KGLog 打印消息的 工具类
所有打印都是通过KLog()进行打印的 在别的地方可以在LogEvent就可以获取到打印事件了
/// <summary>
/// 打印消息的工具拓展类
/// </summary>
public static class KGLog
{
public static bool RunLog = true;
//留的一个打印事件委托
private static Action<string, LogLevel> LogEvent = null;
//这里是打印消息的方法
public static void KLog(this string Logdata,LogLevel logLevel=LogLevel.Common)
{
if (!RunLog)
return;
LogEvent?.Invoke(Logdata,logLevel);
Console.WriteLine("{0}-----------------{1}", Logdata,logLevel.ToString());
}
public static void SetLog(this Action<string, LogLevel> log,bool Run=true)
{
LogEvent = log;
RunLog = Run;
}
}
//打印等级
public enum LogLevel
{
None=0,
Common=1,
Warn=2,
Err=3
}