网络部分知识开发和应用
十月 15, 2022
网络模型
socket结构
iocp(Input/output completion port)
SocketAPI
输入/输出完成端口,常常使用在windows系统中,采用异步的方式对每个socket进行监听和接收。
1 | public void Start(string host, int port) { |
缺点
异步操作可能会产生死锁等线程问题
状态检测Poll
Poll函数
采用同步循环的方式进行监听
1 | if(socket有可读数据) |
服务器实现
1 | 初始化listenfd |
具体实现
1 | static Socket listenfd; |
注意
- 在主循环最后涸用了System.Threading. Thread.Sleep(I), 让程序挂起1毫秒, 这样做的目的是避免死循环, 让 CPU 有个短暂的喘息时间。
- ReadClientfd会返回true或false, 返回false表示该客户端断开(收到长度为
0的数据)。 由于客户端断开后,ReadClientfd会删除clients列表中对应的客户端信息, 导致clients列表改变, 而ReadClientfd又是在foreach (ClientState s in clients.Values)的循环中被调用的, clients列表变化会导致遍历失败, 因此程序在检测到客户端关闭后将退出foreach循环。 - 是将 Poll 的超时时间设置为 0, 程序不会有任何等待。 如果设置较长的超时时间,服务端将无法及时处理多个客户端同时连接的情况。 当然 , 这样设置也会导致程序的CPU占用率很高。
缺点
cpu占用率过高多路复用Select
Select函数
同时检测多个Socket的状态 在设性要监听的Socket列表后 , 如果有一个(或多个)Socket可读 (或可写 , 或发生错误信息), 那就返同这些可读的 Socket, 如果没有可读的 , 那就阻塞
1 | static Socket listenfd; |
过程
服务端使用主循环结构 while(true){…} , 不断地调用 Select 检测 Socket 状态, 其步骤如下:
- 将监听 Socket (listenfd) 和客户端 Socket (遍历 clients 列表)添加到待检测 Socket可读状态的列表 checkList 中。
- 调用 Select, 程序中设置超时时间为 1 秒, 若 l 秒内没有任何可读信息, Select 方法将 checkList 列表变成空列表, 然后返回。
- 对 Select 处理后的每个 Socket 做处理, 如果监听 Socket (listenfd) 可读, 说明有客户端连接, 需凋用 Accept。 如果客户端 Socket 可读, 说明客户端发送了消息(或关闭), 将消息广播给所有客户端
适用空间
由于程序在 Update 中不停地检测数据, 性能较差。 商业上为了做到性能上的极致, 大多使用异步(或使用多线程模拟异步程序)。解决粘包问题的方法
长度信息法
长度信息法是指在每个数据包前面加上长度信息。 每次接收到数据后 , 先读取表示长度的字节 , 如果缓冲区的数据长度大千要取的字节数, 则取出相应的字节 , 否则等待下一次数据接收。
固定长度法
固定一个长度发送消息时多余部分用其他字符填充
结束符号法
在消息最后加一个特殊字符
大端小端问题
来自于平台的不同导致高地址和低地址的顺序不同
相反则是大端模式,常用的X86结构是小端模式 , 很多的ARM、 DSP都为小端模式, 但KEIL CS I则为大端模式 , 有些 ARM 处理器还可以由硬件来选择是大端模式还是小端模式。 也就是说市面上的手机有些采用大端模式, 有些采用小端模式
解决方案
采用Reverse统一顺序。
1 | if(!BitConverter.IsLittleEndian){ |
1 | //int16时 |
BytesArray
用来储存发送和接收的数据结构。
1 | using System; |
异步处理
参数如下
这是客户端部分,当具体到服务器应该去除静态
1 | //定义套接字 |
异步连接
引用致Unity网络游戏实战第二版
1 | //连接 |
异步发送
引用致Unity网络游戏实战第二版
1 | //发送数据 |
异步接收
引用致Unity网络游戏实战第二版
1 | //Receive回调 |
ProtoBuf
和json功能一样作为序列化的工具,当产生消耗更小,优化带宽。
使用
1 | //将protobuf对象序列化为Byte数组 |
proto编写格式
1 | message MsgMove{ |
生成代码
1 | //------------------------------------------------------------------------------ |
具体使用
1 | MsgMove msgMove = new MsgMove(); |
命令行调试
1 |
|
启动指令
1 | xxx.exe -mode server |
查看评论