文章目录
- TCP建立长连接
- 长连接和短连接
- 长连接的优势
- TCP KEEPALIVE
- 心跳包
- 心跳检测步骤
- 断线重连
- 断线重连函数实现
- 实例
- 服务端
- 客户端
- 程序功能
- 演示效果
TCP建立长连接
长连接和短连接
- 长连接是指不论TCP的客户端和服务器之间是否有数据传输,都保持建立的TCP连接;
- 短连接则不同,一旦两者之间的数据传输完毕,则立即断开连接,下次需要传输数据时再重新创建连接
长连接的优势
由于TCP建立连接需要进行三次握手,每次建立连接都需要进行资源消耗,对于频繁请求资源的客户端而言,长连接可减少大量开销
TCP KEEPALIVE
TCP中默认包含一个keep-alive机制用于检测连接是否可用,TCP在链路空闲时定时(默认两小时)发送数据给对方,双方处理结果如下:
- 主机可达,对方收到数据之后响应ACK应答,则连接正常
- 主机可达,但程序退出,对方则发送RST应答,发送TCP撤销连接
- 主机可达,但程序崩溃,对方发送FIN消息
对方主机不响应ACK、RST,继续发送消息直到超时(两小时),就撤销连接
虽然TCP已经有了keep-alive机制保证连接的可靠性,但是其仍有一定的局限性
- keep-alive只能检测连接是否存活,但无法检测其是否可用。例如:socket连接虽然存在,但是无法对该连接进行读写操作,keep-alive机制是无法获知的
- keep-alive的灵活性不够,其默认间隔为两小时,无法及时获知TCP连接情况
- keep-alive无法检测到机器断电、网线拔出、防火墙等导致的断线问题
心跳包
心跳包就是探测性的数据包,因为它像心跳一样每隔固定时间发送,以此来通知服务器自己仍处于存活状态,以保持长连接。心跳包的内容基本没有要求,一般是很小的数据包,或者是仅包含包头的空包
如果不主动关闭socket,操作系统是不会将其关闭的,这样socket所在的进程如果没有挂掉,则socket所占用的资源将一直无法回收。不仅如此,防火墙会自动关闭一定时间没有进行数据交互的连接。因此,我们需要自己实现心跳包,用于长连接的保活、断线处理及资源回收等操作。
一般来说,心跳包的频率为30~40秒,如果对实时性要求较高,则可进一步减小时间间隔
心跳检测步骤
- 客户端定时发送探测包给服务器,同时启动超时定时器
- 服务器接收到检测包之后就回复一个数据包
- 客户端如果接收到服务器的返信,则表示服务器正常,定时器结束
- 如果客户端定时器超时仍没有接收到服务器返信,则表示服务器停止工作
断线重连
长连接断开原因
在长连接通信过程中,双方的所有通信都建立在1条长连接上(1次TCP连接),因此连接需要持续保持双方连接才可使得双方持续通信
长连接会存在断开的情况,而断开原因主要是:
- 长连接所在进程被杀死 NAT超时
- 网络状态发生变化
- 其他不可抗因素(网络状态差、DHCP的租期等等 )
维持长连接的另一个方法是断线重连
如果服务器因为某种故障导致连接无法正常使用,客户端使用心跳检测发现了服务器端掉线,则客户端可进行断线重连操作
我们将之前写的Linux创建tcp连接流程中的程序的客户端进行修改,进而实现服务器断开连接之后,客户端会自动重连
断线重连函数实现
需要注意的是,在判断连接是否断开时,可以判断recv函数是否成功,而非send函数
原因在于,send函数在将数据发送出去就立即返回,不论传输是否成功;
而recv是等数据传输完成之后才会返回,因此使用recv的结果作为判断连接是否成功才更为准确
实例
服务端
客户端
程序功能
先启动服务端,等待客户端进行连接。如果客户端发起连接后,每隔10s发送一个心跳包
- 如果服务端接受到心跳包,则不输入内容,直接等待下一次客户端发送的信息;
- 如果客户端接受到字符串,则等待服务端输入字符串进行回应;
- 如果客户端在发送字符串后,没有收到回应信息,则重新发起连接请求;
演示效果
程序手动在服务端执行过程中,输入ctrl+C关闭服务端进程,在客户端重连次数之内再重新打开即可
- 客户端
- 服务端