socket的状态含义

通过 netstat 命令查看网络状态,其中有一列展示的是 socket 的状态,熟练掌握这些状态的含义有助于连接状态的分析与问题排查。

如下是通过 netstat -natp 命令获取到的一些网络信息

1
2
3
4
5
6
7
8
9
10
11
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp 0 0 192.168.1.7:22 192.168.1.5:64582 ESTABLISHED -
tcp 0 0 192.168.1.7:22 192.168.1.5:49651 ESTABLISHED -
tcp 0 0 192.168.1.7:22 192.168.1.5:49679 ESTABLISHED -
tcp6 0 0 :::8080 :::* LISTEN 4797/java
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
tcp6 0 0 ::1:59296 ::1:8080 TIME_WAIT -

可以看到倒数第二列是 socket 的状态,接下来我们就来看下每种状态的含义(下面的数据来自于 netstat 命令的 man page)

CLOSED

socket 已关闭,未在使用中

LISTEN

socket 正在监听连接请求。server 启动时,会先调用 bind 系统调用绑定端口,然后调用 listen 系统调用监听连接请求,此时 ServerSocket 会处于 LISTEN 状态

bind 的方法签名如下:

1
2
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);

当通过 socket() 系统调用创建了一个 socket 之后,该 socket 还未分配到地址(address),此时需要调用 bind 命令将 addr 指定的地址绑定到 sockfd 文件描述符所代表的 socket 上

listen 的方法签名如下:

1
int listen(int sockfd, int backlog);

listen 系统调用将 sockfd 代表的 socket 标记为 被动的 socket,也就是说这个 socket 用于监听连接请求,当一个连接请求完成3次握手并建立连接后,可以通过 accept 系统调用获取这个连接。其中 sockfd 是一个文件描述符,它指向一个 SOCK_STREAMSOCK_SEQPACKET 类型的 socket。backlog 定义了 待接受连接队列 的最大长度,如果一个连接请求到达后队列已经满了,那么客户端将会收到一个 ECONNREFUSED,但是如果底层协议支持重传,这个连接请求将会被忽略,客户端会通过重传尝试建立连接。

SYN_SENT

客户端 socket,已经向服务端发送过握手请求,尝试建立连接

SYN_RCVD

服务端 socket,已经接收到了一个来自远端的连接请求

ESTABLISHED

socket 连接已建立完成

CLOSE_WAIT

四次挥手中被动关闭的一方,对方已经发送了关闭请求。本地系统正在等待本地应用程序关闭连接

LAST_ACK

四次挥手中被动关闭的一方,对方已经发送了关闭请求。本地应用已经调用 close() 关闭连接,本地系统正在等待对方的 ack 回复

FIN_WAIT_1

四次挥手中主动关闭的一方,本地应用已经调用了 close 关闭连接,还未收到对方的 ack 回复,系统等待对方关闭半连接

FIN_WAIT_2

四次挥手中主动关闭的一方,本地应用已经调用了 close 关闭连接,并且已经收到了对方的 ack 回复,系统等待对方关闭半连接

CLOSING

本地和对方同时关闭连接,并且本地还未收到对方对 close 请求的 ack

TIME_WAIT

四次挥手中主动关闭的一方,本地应用已经调用了 close 关闭连接,对方也已经关闭了它的半连接,本地系统还需等待一段时间,以确认对方收到了最后一个 ack