Socket
- Socket 编程
- 针对 TCP 应该如何 Socket 编程?
- listen 时候参数 backlog 的意义?
- accept 发送在三次握手的哪一步?
- 客户端调用 close 了,连接断开的流程是什么?
Socket 编程

- 服务端和客户端初始化
socket
,得到文件描述符 - 服务端调用
bind
,将绑定 IP 和端口 - 服务端调用
listen
,进行监听 - 服务端调用
accept
,等待客户端连接 - 客户端调用
conncet
,向服务端的地址和端口发起连接请求 - 服务端
accept
返回用于传输的socket
的文件描述符 - 客户端
wirte
写入数据;服务器调用read
读取数据 - 客户端断开连接时,会调用
close
,那么服务端read
读取数据的时候,就会读取到 EOF ,待处理完数据后,服务端调用close
,表示连接关闭。
服务器调用 accept
时,连接成功了会返回一个已完成连接的 socket
,后续用来传输数据,所以监听的 socket
和真正用来传输数据的 socket
,一个叫监听 socket
,一个叫作已完成连接 socket
。成功建立连接后,双方开始通过 read
和 write
读写数据,就像往一个文件流里写东西一样。
客户端 connect 成功返回是在第二次握手,服务端 accept 成功返回实在第三次握手成功之后。
backlog
Linux 内核会维护两个队列:
- 未完成连接队列(SYN 队列) :接收到一个 SYN 建立连接请求,处于
SYN_RCVD
状态 - 已完成连接队列(Accpet 队列):已完成 TCP 三次握手的过程,处于
ESTABLISHED
状态
int listen(int socketfd, int backlog)
socketfd
为 socket
文件描述符, backlog
为 SYN 队列的大小, Linux 2.2 后, backlog
为 Accpet 队列的大小。
但上限值是内核参数 somaxconn
的大小,即 Accpet 队列长度 = min(backlog, somaxconn)
。
TCP_NODELAY
配置是否关闭 nagle 算法。
setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(int));
TCP_CORK
功能类似于在发送数据管道出口处插入一个“塞子”,使得发送数据全部被阻塞,直到取消 TCP_CORK
选项(即拔去塞子)或被阻塞数据长度已超过 MSS
才将其发送出去。
用户层可通过 setsockopt()
系统调用设置 TCP 套接字的 TCP_CORK
选项。开启时,内核将阻塞不完整的报文,当关闭此选项时,发送阻塞的报文。
TCP_CORK
强于 TCP_NODELAY
,在大部分的情况下,即使通过设置 TCP_NODELAY
而关闭 Nagle 算法,但是开启了 TCP_CORK
,数据也会被缓存而不是立即发送。
setsockopt(sock_fd, IPPROTO_TCP, TCP_CORK, (char *)&value, sizeof(int));
SO_LINGER
struct linger { int l_onoff; /* Linger active */ int l_linger; /* How long to linger for */ };
在 Linux 系统中,设置了 SO_LINGER
即 l_onoff
为 1 时1:
l_linger
为 0 则导致所有数据丢失且连接立即中止。
l_linger
非 0 则:
- 待发送的数据全部得到了对端确认,返回值 0
- 发生信号中断或异常(比如意外收到对端发送过来的数据)或超时,返回值 0
一种使用方法1:
- 设置
SO_LINGER
选项l_onoff
非 0 而l_linger
为 0 - 调用函数
shutdown(sock_fd, SHUT_WR)
- 设置超时计时器
- 调用函数
read(sock_fd)
阻塞等待,直到读到EOF
或被超时器中断 - 执行函数
close(sock_fd)
或者exit(0)
进程退出
Reference
- 图解网络-小林 coding-v3.0.pdf
Footnotes:
Socket 选项系列之 SO_LINGER,链接:http://www.lenky.info/archives/2013/02/2220