全连接队列
监听套接字
使用socket接口创建一个套接字,然后bind给套接字绑定地址,最后listen将套接字设置为监听套接字。监听套接字以前理解是三元组标识,后面看了netstat,觉得应该是五元组,只不过它这个五元组是{协议,本地ip,本地端口,0.0.0.0,*},也就是对端的地址无论是ip还是port都是任意的,我们既可以三元组也可以五元组,这个不重要
理解 listen 接口
int listen(int sockfd, int backlog);
第一个参数很easy,不就是套接字文件描述符嘛,主要看第二个backlog,这个参数是用来指定监听套接字的全连接队列大小的,linux中全连接队列大小通常是backlog+1
结合代码理解全连接队列
test_server.cc
#include \"tcp_socket.hpp\"int main(int argc, char* argv[]) {if (argc != 3) {printf(\"Usage ./test_server [ip] [port]\\n\");return 1;}TcpSocket sock;bool ret = sock.Bind(argv[1], atoi(argv[2]));if (!ret) {return 1;}ret = sock.Listen(2);if (!ret) {return 1;}// 客户端不进行 acceptwhile (1) {sleep(1);}return 0;}
test_client.cc
#include \"tcp_socket.hpp\"int main(int argc, char* argv[]) {if (argc != 3) {printf(\"Usage ./test_client [ip] [port]\\n\");return 1;}TcpSocket sock;bool ret = sock.Connect(argv[1], atoi(argv[2]));if (ret) {printf(\"connect ok\\n\");} else {printf(\"connect failed\\n\");}while (1) {sleep(1);}return 0;}
服务器端创建好监听套接字,并设置backlog为2,那全连接队列大小就是3,后面服务器端一直死循环,不进行accept。前三个客户端过程都一样,进行创建套接字,然后connect开始三次握手,发送SYN包,服务器端收到后在监听套接字的半连接队列里创建struct request_sock,然后响应SYN+ACK包,客户端主机收到后,进程从套接字通用等待队列上唤醒,唤醒后connect执行完毕返回,也会进入死循环,当然这要等进程重新被调度再走这些,在收到包后还要返回ACK包,服务器端收到后会将监听套接字半连接队列中的struct request_sock升级成全连接队列中的struct sock,三个客户端都是这个式,我们来看第4个客户端,客户端同样connect触发三次握手发送SYN包,服务器端收到后同样的在监听套接字的半连接队列中创建对应结构,然后响应SYN+ACK包,客户端收到后,进程被唤醒,然后响应ACK包,服务器端收到后因为全连接队列满了,那半连接队列中的struct request_sock就没法升级,所以该通信套接字会卡在SYN_RECV,客户端的通信套接字却因为收到了SYN+ACK所以是ESTABLISHED状态
用netstat -anptu查看一下
客户端的四个通信套接字全是ESTABLISHED,没问题,服务器端一个LISTEN套接字,三个ESTABLISHED,一个SYN_RECV,和我们预期一摸一样
netstat命令
netstat其中一个作用是查看套接字
(1) 查看所有 TCP 连接
netstat -ant
-a
:显示所有连接(包括监听和通信)-n
:显示数字-t
:仅显示 TCP 连接
(2) 查看所有 UDP 连接
netstat -anu
-u
:仅显示 UDP 连接
(3) 查看监听状态的端口
netstat -tuln
-l
:仅显示监听(LISTEN)状态的套接字
(3) 最常用的配合
netstat -anptu
属性行中Recv-Q和Send-Q是什么?
1. 基础概念
Recv-Q
Send-Q
2. 不同状态下的含义
(1) 对于 LISTEN
状态的套接字(服务端)
-
Recv-Q:
已完成三次握手,全连接队列中等待被accept()
系统调用取走的连接数。
示例:Recv-Q: 5
表示全连接队列中有 5 个连接等待处理。 -
Send-Q:
全连接队列的最大长度,linux中为backlog+1。
示例:Send-Q: 128
表示全连接队列的大小为 128。
(2) 对于 ESTABLISHED 状态的套接字(已建立的连接)
-
Recv-Q:
内核已接收但应用层未读取的数据量(堆积在接收缓冲区)。
正常情况:应为 0 或较小值。若持续增长,可能表示应用层读取过慢。 -
Send-Q:
已发送但未收到对方 ACK 应答的数据量(在发送缓冲区中等待确认)。
正常情况:在网络无拥塞时应快速清零。若持续增长,可能表示网络延迟或丢包。
TCP 套接字状态解析
netstat
输出的 State
列显示 TCP 连接状态,常见状态如下:
bind()
+ listen()
后)sshd
监听 22 端口curl google.com
发起连接时close()
后close()
netstat
中显示)