总结
- 其实现在用TCP很少了,我在群里看到的目前流行的都是用KCP
- 就是在UDP的基础上采用TCP的那一套保证数据的方式
- TCP本身是数据传输可靠的连接,额外需要注意的有以下几点
粘包半包处理
场景
-
TCP的运作机制是这样的,操作系统会给每个Socket设置一个缓存区,当你调用
socket.EndReceive
或者socket.Receive
的时候,会把缓存区的数据提取出来。
-
因为TCP本身是基于字节流的连接,如果你连续向服务端发送两条消息。
-
这两个消息的字节全部在缓存区,提取的时候都提出来了,在一个
byte[]
里面,那你要怎么划分这些字节呢? -
所以你除了定义消息类型外,所以还需要定义消息长度
#####解决方案
心跳包
场景
- 比如你用手机玩游戏,但是突然断网了
- 但是服务端还保存有你的socket连接信息,这样对服务端是一个额外的负担。
- 其实TCP底层有心跳包机制,但是它的监听时间太久了,就是两个小时你没有发送消息时,他才会给你断掉
- 所以我们需要自己实现一套心跳包
解决
- 逻辑如下
发送队列
问题
- 这个问题的产生是因为操作系统给socket设置的缓存区是有限制的,貌似是8kb
- 当你一次发送大量数据
- 服务端网络不好,客户端数据发送不出去导致多个信息堆积在缓存里
- 都会导致有限的发送数据
- 即
socket.Send()
和socket.EndSend()
方法都会返回一个整数,即成功发送到系统层面缓冲区的数据为多少,但是剩下的需要继续发送
解决
- 也可以直接把系统层面的缓冲区设置的很大来解决
大小端处理
问题
- 这个问题是数据的大小端问题
- 其实我不知道为什么要处理这种底层的问题
- 就像一个类对象被序列化为字节数组,那需要关注大小端吗
- 为什么只有数字需要关注大小端呢?
TCP设置选项
- NoDelay[Nagle算法]
- 因为TCP底层用IP,IP底层还有链路层协议,每个协议都会消息体前面加一堆字节的消息头
- 想象一下,如果你有一堆
1
字节的消息发送,每个被底层打包后变成40
字节,这种额外的消息头就占用带宽和消耗流量 - 所以
Nagle算法
会检测,如果你发送数据都很小,就会把他们打包发送,造成延迟 - 对于一些即时性要求很高的游戏,需要设置
NoDelay=true
关闭Nagle
算法 - 复用端口
- 一般是服务端为了及时重启,但这时刚刚崩溃的服务端还没有把socket释放,会导致端口占用的错误
- 所以设置复用端口就可以很好的解决这个问题
- 但是这个问题也会出现一些莫名奇妙的情况
- TTL
- 可以设置发送数据包的最大路由器跳数。当超过这个跳数后,路由器就会丢弃数据。
- 这是为了避免陷入死循环,当服务器挂掉后。可能出现,A——》B——》C——》A这样的死循环
- lingState
- 为了解决关闭连接时的额外操作
- sendBuffSize
- 设置socket系统缓存区的大小。