TCP shutdown VS HTTP KeepAlive

Building an HTTP client for some performance testing purposes. Multiple sockets, I/O multiplexing, two threads. One sender pushing pipelined requests and one receiver dragging all server responses

In order to simplify program logic I tried to shutdown the writer end after all requests has been sent

shutdown (s, SHUT_WR);

at the same time responses are being read from the other thread. I thought that since I used SHUT_WR, the receiver should be able to get data as nothing happened.

It didn't work. Data stops at half way.

I tried with HTTP/1.1 Connection: KeepAlive, Connection: Close. Neither worked out the trick. Down stream stops at ~60k every time.

After some sharp pointers from my old friend Bluntblade, Wireshark came into rescue.


When the shutdown call is triggered, client sends an FIN packet to server. Upon receiving this packet, server may stop serving further content.

D'm it!

TCP连接中,如果`send`函数卡死且`close``shutdown`函数无效,通常是由于以下几种原因: 1. **阻塞模式下的`send`函数**:`send`函数在阻塞模式下,如果发送缓冲区已满,会一直等待直到有空间可写。如果对端没有读取数据,缓冲区可能会一直满,导致`send`函数卡死。 2. **对端未正确关闭连接**:如果对端没有正确关闭连接(例如,对端进程崩溃或网络断开),本端的`close``shutdown`函数可能不会立即返回,导致看起来像是无效。 3. **网络问题**:网络故障或延迟可能导致数据无法发送出去,`send`函数会一直等待。 4. **信号中断**:如果`send`函数被信号中断,可能会返回`EINTR`错误,但如果没有正确处理这个错误,函数会看起来像是卡死。 ### 解决方法 1. **使用非阻塞模式**:将套接字设置为非阻塞模式,这样`send`函数在缓冲区满时会立即返回`EAGAIN`或`EWOULDBLOCK`错误,而不是卡死。 ```c int flags = fcntl(socket_fd, F_GETFL, 0); fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK); ``` 2. **设置超时**:使用`select`或`poll`函数来设置发送超时时间,避免无限等待。 ```c struct timeval tv; tv.tv_sec = 5; // 5秒超时 tv.tv_usec = 0; setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv)); ``` 3. **检查对端状态**:使用`select`或`poll`函数来检查对端是否仍然连接。 ```c fd_set readfds; FD_ZERO(&readfds); FD_SET(socket_fd, &readfds); struct timeval tv; tv.tv_sec = 5; // 5秒超时 tv.tv_usec = 0; int ret = select(socket_fd + 1, &readfds, NULL, NULL, &tv); if (ret == 0) { // 超时 } else if (ret > 0) { // 检查对端是否关闭连接 char buf; int n = recv(socket_fd, &buf, 1, MSG_PEEK); if (n == 0) { // 对端关闭连接 } } ``` 4. **正确处理信号**:在信号处理函数中设置一个标志位,然后在`send`函数返回后检查这个标志位。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值