TCP全连接队列与TCP通信的深刻理解

📅 发布时间:2026/7/11 21:49:34 👁️ 浏览次数:
TCP全连接队列与TCP通信的深刻理解
关于listen函数listen() 是网络编程中基于 TCP/IP 协议的核心系统调用作用是将主动连接的套接字socket转换为被动监听套接字并设置待处理连接的队列长度让操作系统开始监听客户端的连接请求。#includesys/socket.hintlisten(intsockfd,intbacklog);参数说明sockfd: 已创建并绑定bind的套接字描述符文件句柄backlog: 监听队列的最大长度等待被accept()处理的连接数上限返回值成功返回 0失败返回 - 1并设置errno错误码关于listen函数的第二个参数三次握手建立连接的过程由内核 TCP 协议栈自主完成不需要等待用户层调用accept()。accept ()只是 “取连接” 的动作accept()不参与三次握手它的唯一作用是从内核的「全连接队列」中取出一个已完成三次握手的连接交给用户层使用。服务器来不及 accept 的影响如果用户层代码处理慢比如业务逻辑耗时accept() 调用不及时全连接队列会堆积已完成三次握手的连接 —— 直到队列满。全连接队列满了之后新的三次握手请求会被内核拒绝或丢弃导致客户端连接超时 / 失败。listen(sock, backlog)的 backlog 核心是限制 [全连接队列已完成三次握手] 的最大长度通常是 backlog 1。半连接队列 vs 全连接队列队列类型别名存放的连接状态触发入队时机触发出队时机长度限制来源半连接队列SYN 队列SYN_RECV服务器收到客户端 SYN收到客户端 ACK三次握手完成内核参数 tcp_max_syn_backlog全连接队列ACCEPT 队列ESTABLISHED三次握手完成用户层调用accept ()listen()的 backlog 参数listen的第二个参数的意义为全连接队列中允许已经建立三次握手成功的连接的个数的最大值 backlog 1理解全连接队列原理回忆文件系统的文件描述符文件列表和进程的关系进程、sockfd、端口的核心关系实体本质定位存储位置核心作用进程资源分配的基本单位内存task_struct包含文件描述符表管理多个 sockfdsockfd进程内访问 socket 的凭证进程 fd 数组映射到内核 struct socket/struct sock是进程操作网络资源的唯一入口端口网络层的“应用标识”内核端口哈希表关联到 struct sock让网络包能找到对应的进程/sockfd可视化核心映射链路进程task_structfiles_structfd 表sockfd3 → struct file → struct socket → struct socksockfd4 → struct file → struct socket → struct sock端口 8080内核哈希表TCP0.0.0.0:8080 → sock1端口 9090内核哈希表TCP0.0.0.0:9090 → sock2核心结论进程与 sockfd一对多一个进程可拥有多个 sockfd每个 sockfd 对应一个独立的 socket 资源sockfd 与端口默认一对一一个 sockfd 绑定一个端口端口哈希表确保唯一性特殊场景可多对一多个 sockfd 绑定同一端口进程与端口间接关联通过 sockfd 映射可一对多一个进程绑定多个端口也可多对一多个进程绑定同一端口。“一对多”的核心场景场景1一个进程 → 多个 sockfd必然原因进程的核心诉求是处理多网络资源比如服务器既监听 8080 端口又监听 9090 端口或一个进程同时连接多个客户端底层逻辑进程的files_struct是一个可扩展的 fd 数组默认 1024可通过ulimit -n调整每个下标对应一个 sockfd指向独立的struct socket/struct sock示例// 一个进程创建 2 个 sockfd绑定不同端口intsockfd1socket(AF_INET,SOCK_STREAM,0);// 绑定 8080intsockfd2socket(AF_INET,SOCK_STREAM,0);// 绑定 9090场景2一个进程 → 多个端口常见原因服务器需要提供多服务比如一个进程同时提供 HTTP80、HTTPS443服务底层逻辑进程创建多个 sockfd每个 sockfd 分别绑定不同端口内核端口哈希表中不同 keyTCPIP端口指向不同的struct sock注意同一进程的多个 sockfd 不能绑定完全相同的「协议IP端口」会返回EADDRINUSE但可绑定「不同 IP同一端口」比如 sockfd1 绑定 192.168.1.100:8080sockfd2 绑定 192.168.1.101:8080。场景3一个端口 → 多个 sockfd特殊需内核选项原因实现端口复用比如多进程/线程负载均衡、TIME_WAIT 端口快速复用底层前提需给 sockfd 设置SO_REUSEADDR/SO_REUSEPORT选项SO_REUSEADDR允许 TIME_WAIT 状态的端口被重新绑定或同一 IP端口绑定不同协议TCP/UDPSO_REUSEPORTLinux 3.9允许多个 sockfd甚至不同进程的绑定同一「TCP0.0.0.0:端口」内核会将请求负载均衡到不同 sockfd示例intopt1;setsockopt(sockfd,SOL_SOCKET,SO_REUSEPORT,opt,sizeof(opt));// 开启端口复用bind(sockfd,(structsockaddr*)addr,sizeof(addr));// 多个 sockfd 可绑定同一端口“多对一”的特殊场景场景1多个进程 → 同一个端口SO_REUSEPORT底层逻辑内核端口哈希表中同一 keyTCP0.0.0.0:8080会挂多个struct sock实例收到网络包时内核通过哈希算法将包分发到其中一个sock进而找到对应进程的 sockfd典型用途多进程监听同一端口实现请求负载均衡比如 Nginx 的worker_processes多进程模型。场景2多个 sockfd → 同一个端口同一进程内底层逻辑同一进程内创建多个 sockfd都设置SO_REUSEPORT后绑定同一端口内核会将请求分发到不同 sockfd提升并发处理能力注意无SO_REUSEPORT时第二个 bind 会返回EADDRINUSE。通俗类比进程 一家公司sockfd 公司里的员工工号每个员工对应一个工号一个公司可有多员工端口 公司的对外窗口比如 80 窗口负责接待 HTTP 客户443 窗口负责 HTTPS 客户默认规则一个窗口端口默认只安排一个员工sockfd接待SO_REUSEPORT给一个窗口安排多个员工客户来了随机分配给其中一个提升效率。