半关闭状态

一次TCP四次挥手的过程如上图所示。设左侧为客户端,右侧为服务端,当客户端发起FIN而关闭其写通道时(对应服务端读通道),服务端进入close_wait状态,但希望推送完所有数据后再关闭整个连接。此时连接处于半关闭状态,客户端只能读,服务端只能写。
待服务端发送完所有数据并发送一个FIN后,客户端响应ACK,服务端收到ACK后知道客户端收到了所有数据,此时才能关闭服务端的写通道。
实现方法
客户端:调用shutdown(SHUT_WR) 发送⼀个 FIN 包,并且标记该 socket 为 SEND_SHUTDOWN;
服务端:收到 FIN 包并标记该 socket 为RCV_SHUTDOWN;此时就进入半关闭状态;
如果使用epoll实现,若⼀个Socket同时标记为 SEND_SHUTDOWN 和 RCV_SHUTDOWN;那么会触发 EPOLLHUP 事件;
如果⼀个Socket被标记为 RCV_SHUTDOWN;那么会触发 EPOLLRDHUP事件。
tcp-keepalive
tcp-keepalive 是在TCP传输层实现的探活机制,与应用层无关,因此应用程序无法介入。这也是为什么应用层往往还需要实现自己的心跳监测机制,因为假如应用层进程出现阻塞或死锁,传输层完全无法感知到,依然会正常发送探活包,此时tcp-keepalive实际并不能起到作用。
开启 tcp-keepalive
方法1 Linux系统全局开启
$ sudo vim /etc/sysctl.conf
net.ipv4.tcp_keepalive_time=7200 # 两端多久没有数据交换后,开始发送 keepalive syn 探活包(单位秒)
net.ipv4.tcp_keepalive_intvl=75 # 发送多少次探活包
net.ipv4.tcp_keepalive_probes=9 # 探活包发送间隔
$ sysctl -p # 使配置⽣效
方法2 setsockopt 设置 socket
设置开启:
int val = 1;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val);
配置参数:
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)); // tcp_keepalive_time
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)); // tcp_keepalive_intvl
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)); // tcp_keepalive_probes
本文介绍了TCP连接中的半关闭状态,详细解释了客户端和服务端如何进入此状态,以及如何通过shutdown系统调用实现。同时,讨论了tcp-keepalive作为传输层的探活机制,虽然不能解决应用层问题,但仍然是保持连接活性的重要手段。最后提到了开启tcp-keepalive的两种方法,包括Linux系统的全局开启和通过setsockopt设置socket。
391

被折叠的 条评论
为什么被折叠?



