#include <sys/socket.h>
int shutdown(int sockfd, int how);
概述
shutdown() 调用会导致与 _sockfd_ 关联的套接字上的全双工连接全部或部分关闭。如果 _how_ 是 SHUT_RD,则不允许进一步接收数据。如果 how 是 SHUT_WR,则不允许进一步发送数据。如果 how 是 SHUT_RDWR,则不允许进一步接收和发送数据。
shutdown(SHUT_RD)
执行 shutdown(SHUT_RD) 仅关闭本地套接字的读方向功能。
本地行为
- 丢弃接收缓冲区数据:内核会清空接收缓冲区中未读取的数据。
- 停止接收数据:应用层通过
recv()或read()读取数据时会返回 0(EOF)。 - 静默处理对端数据:即使对端继续发送数据,本地 TCP 协议栈会丢弃这些数据(不会进入接收缓冲区),但仍会回复 ACK 确认报文(避免对端重传)。
对端行为
- 无
FIN报文:由于SHUT_RD不涉及写方向关闭,本地不会发送FIN报文,因此对端无法通过协议感知到读方向的关闭****。 - 对端仍可发送数据:对端的
send()操作仍会成功(数据进入发送缓冲区并通过 TCP 传输),但本地会静默丢弃这些数据。 - 对端可能误判:若对端依赖本地的读操作反馈(如业务层协议),可能导致对端长时间等待响应,最终因超时触发连接重置(如
ECONNRESET错误)。例如,对端(业务层协议)发送了一个消息,期望本地接收到消息后,给它一个回复。但由于本地读端已关闭,无法收到对端发送的消息,自然也不可能给他一个回复,对端(业务层协议)可能经过多次尝试失败后,判断本地已经关闭。
shutdown(SHUT_WR)
本地执行 shutdown(SHUT_WR) 会关闭本地套接字的写方向,触发 TCP 协议的四次挥手流程。
图网上随便找的。

本地行为
- 立即发送 FIN 报文
调用shutdown(SHUT_WR)后,内核会立即发送FIN报文给对端,表示本地不再发送数据。此时本地套接字进入FIN_WAIT_1状态。 - 发送缓冲区处理
- 若发送缓冲区有未发送数据,内核会尝试全部发送****。
- 后续对套接字的写操作(如
send())会返回-1,并设置errno为EPIPE或触发SIGPIPE信号****。
- 状态流转
- 收到对端的 ACK 后,本地状态转为
FIN_WAIT_2(等待对端FIN报文)。 - 收到对端
FIN后,本地回复 ACK 并进入TIME_WAIT状态。
- 收到对端的 ACK 后,本地状态转为
对端行为
-
接收 FIN 报文
- 对端内核收到
FIN后,标记sk->sk_shutdown |= RCV_SHUTDOWN;,套接字进入CLOSE_WAIT状态,并回复 ACK。核心逻辑位于net/ipv4/tcp_input.c中的tcp_fin()函数。 - 对端应用层的
read()行为如下:-
接收缓冲区仍有数据:应用层仍可通过
read()读取接收缓冲区中已有的数据,返回剩余数据长度。 -
接收缓冲区没有数据:应用层
read()(无论阻塞还是非阻塞式 scoket)都会立即返回0(EOF)。 -
不接收新数据:若本地(主动关闭方)在发送
FIN后仍有数据到达,读端(被动关闭方)的 TCP 协议栈会丢弃这些数据(不会进入接收缓冲区),但回复ACK确认包以避免重传。正常情况下的
read()行为(没有收到 fin 包,更准确地说是读端未关闭的情况下):- **socket 阻塞模式:**无数据进程/线程阻塞;数据到达,返回实际读取字节数。
- **scoket 非阻塞模式:**内核接收缓冲区有数据返回实际读取字节数;无数据,立即返回 -1,设置
errno为EAGAIN或EWOULDBLOCK。
-
- 对端内核收到
-
数据发送与关闭
- 对端仍可继续发送数据,本地会接收并处理(若未关闭读方向
SHUT_RD)。 - 对端调用
close()时,发送自己的FIN报文,完成四次挥手。
- 对端仍可继续发送数据,本地会接收并处理(若未关闭读方向
1110

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



