linux系统之一 全连接与半连接队列
一、全连接与半连接队列
在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:
半连接队列,也称 SYN 队列;
全连接队列,也称 accepet 队列;
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,
接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。
二、相关调试命令
1.netstat -s
可查看到当前系统半连接队列满导致的丢包统计,但该数字记录的是总丢包数
2.半连接队列长度Linux内核中,主要受tcp_max_syn_backlog影响
$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog 128
3.全连接队列长度是应用程序调用listen时传入的backlog以及内核参数net.core.somaxconn二者之中较小的那个
$ cat /proc/sys/net/core/somaxconn 128
// 函数:int listen(int s, int backlog)
4.在服务端可以使用 ss
命令,来查看 TCP 全连接队列的情况
# -l 显示正在监听(listening)的socket
# -n 不解析服务名称
# -t 只显示tcp socket
$ ss -ntl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 1 128 127.0.0.1:6000 *:*
Recv-Q:当前全连接队列的大小,也就是当前已完成三次握手并等待服务端 accept() 的 TCP 连接个数;
Send-Q:当前全连接最大队列长度,上面的输出结果说明监听 6000 端口的 TCP 服务进程,最大全连接长度为 128;
5.netstat -anlp 可查看具体socket状态
$ netstat -anlp | grep 6000 tcp 1 0 127.0.0.1:6000 0.0.0.0:* LISTEN 21110/./server tcp 0 0 127.0.0.1:6000 127.0.0.1:39932 ESTABLISHED - #客户端connect返回了,服务端accept未返回 tcp 0 0 127.0.0.1:6000 127.0.0.1:39712 ESTABLISHED 21110/./server tcp 0 0 127.0.0.1:39712 127.0.0.1:6000 ESTABLISHED 21256/./client tcp 0 0 127.0.0.1:39932 127.0.0.1:6000 ESTABLISHED 21375/./client
6.ps可查看进程的状态
$ ps -a PID TTY TIME CMD 14228 pts/8 00:00:00 ps 21110 pts/11 00:00:00 server 21256 pts/10 00:00:00 client 21375 pts/9 00:00:00 client $ ps -t pts/11 -o pid,ppid,tty,stat,args,wchan | grep server #pts/11 表示伪终端号6
PID PPID TT STAT COMMAND WCHAN 21110 18216 pts/11 S+ ./server sk_wait_data $ ps -t pts/10 -o pid,ppid,tty,stat,args,wchan | grep client
PID PPID TT STAT COMMAND WCHAN 21256 18172 pts/10 S+ ./client n_tty_read $ ps -t pts/9 -o pid,ppid,tty,stat,args,wchan | grep client
PID PPID TT STAT COMMAND WCHAN 21375 18096 pts/9 S+ ./client n_tty_read
三个网络进程的STAT列都是“S+”,表明进程在为等待某些资源而睡眠。“+”位于后台的进程组。
Linux在进程阻塞于accept或者connect时,输出inet_csk_accept或者wait_for_connect;
在进程阻塞于套接字输入或输出时,输出tcp_data_wait或者sk_wait_data;
在进程阻塞于终端I/O时,输出n_tty_read(有的文档写输出read_chan)
三、服务端代码

#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<unistd.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> int main() { //创建用于监听的套接字,这个套接字是一个文件描述符,用于检测有没有客户端发起一个新的连接 int listenfd = socket(AF_INET,SOCK_STREAM,0); assert(listenfd != -1); struct sockaddr_in addr; memset(&addr,0,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port =htons(6000);//转化端口号 addr.sin_addr.s_addr = inet_addr("127.0.0.1");//回环地址 // 将得到的监听的文件描述符和本地的IP端口进行绑定 int res = bind(listenfd,(struct sockaddr*)&addr,sizeof(addr)); assert(res != -1); //设置监听(成功之后开始监听,监听的是客户端的连接) res = listen(listenfd,5); assert(res != -1); //通信 while (1) { struct sockaddr_in cli_addr; socklen_t cli_len = sizeof(cli_addr); int c = accept(listenfd,(struct sockaddr*)&cli_addr,&cli_len); if(c == -1) { printf("Get One Client Link Error\n"); continue; } while (1) { char buff[128] = {0}; int n = recv(c,buff,127,0);//读取数据放在buff中,一次读取127个 if(n <= 0) { printf("Client will unlink\n"); break; } printf("%d : %s\n",c,buff); send(c,"OK",2,0); } close(c); } //断开连接,关闭套接字(四次挥手) close(listenfd); return 0; }
四、客户端代码

#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<unistd.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> int main() { //创建一个通信的套接字,需要指定服务器的IP和端口号y int sockfd = socket(AF_INET,SOCK_STREAM,0); assert(sockfd != -1); struct sockaddr_in ser_addr; memset(&ser_addr,0,sizeof(ser_addr)); ser_addr.sin_family = AF_INET; ser_addr.sin_port =htons(6000);//转化端口号 ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//回环地址 //连接服务器,需要知道服务器绑定的IP和端口 int res = connect(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr)); assert(res != -1); //通信 while (1) { printf("input: "); char buff[128] = {0}; fgets(buff,127,stdin); if(strncmp(buff,"end",3) == 0) { break; } send(sockfd,buff,strlen(buff) - 1,0);//\n不发 memset(buff,0,128); recv(sockfd,buff,127,0); printf("%s\n",buff); } //断开连接 close(sockfd); return 0; }
注:先启动服务端,再启多个客户端
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端