
通过断点调试和人工延迟实验我完整地观察到了阻塞函数的三次唤醒/变化场景分别对应 TCP 通信中队列积压、连接建立和数据传输三个阶段的内核行为1.sleep()期间观察积压已完成连接队列堆积当我在服务端accept()之前插入sleep(50)并启动服务后连续运行多个客户端。此时服务端尚未调用accept()但客户端已陆续完成三次握手。通过ss -lntp命令我看到Recv-Q已完成连接队列的当前积压数变为2而Send-Q显示为5即backlog上限。这直观地验证了accept()只是从队列中取走连接而连接的入队由内核在握手完成后自动完成两者是解耦的。2.accept()阻塞返回监听队列有连接就绪当我在客户端connect()处打断点并继续执行时服务端的accept()从阻塞状态返回。这是因为内核已将连接放入已完成队列accept()从队头取走连接并返回同时打印出客户端地址信息。3.read()阻塞返回接收缓冲区有数据到达当我在客户端write()处打断点并继续执行时服务端的read()从阻塞状态返回。这是因为客户端数据已到达内核接收缓冲区read()读取数据并继续执行。代码调试 实验小结触发操作观察对象现象/变化内核机制运行多个客户端 服务端sleep(50)ss -lntp的Recv-Q积压数变为2backlog为5已完成连接队列暂存了等待accept()的连接客户端connect()单步执行服务端accept()阻塞返回打印客户端 IP已完成连接队列非空accept()取走连接客户端write()单步执行服务端read()阻塞返回打印接收到的消息接收缓冲区非空read()读取数据服务端#includearpa/inet.h#includecstring#includeiostream#includesys/socket.h#includeunistd.husingnamespacestd;intmain(){// 1. 创建 TCP 套接字intfdsocket(AF_INET,SOCK_STREAM,0);if(fd-1){cerrsocket() failedendl;return-1;}// 2. 设置端口复用intopt1;if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,opt,sizeof(opt))-1){cerrsetsockopt() failedendl;close(fd);return-1;}// 3. 绑定地址和端口sockaddr_in addr{};addr.sin_familyAF_INET;addr.sin_addr.s_addrhtonl(INADDR_ANY);addr.sin_porthtons(8888);if(bind(fd,(sockaddr*)addr,sizeof(addr))-1){cerrbind() failed (port 8888 may be in use)endl;close(fd);return-1;}// 4. 开始监听if(listen(fd,5)-1){cerrlisten() failedendl;close(fd);return-1;}coutServer listening on port 8888...endl;// 5. 接受客户端连接sockaddr_in client_addr{};socklen_t lensizeof(client_addr);intcfdaccept(fd,(sockaddr*)client_addr,len);if(cfd-1){cerraccept() failedendl;close(fd);return-1;}// 6. 输出客户端信息点分十进制格式charip_str[INET_ADDRSTRLEN];inet_ntop(AF_INET,client_addr.sin_addr,ip_str,sizeof(ip_str));coutClient connected from ip_str:ntohs(client_addr.sin_port)endl;// 7. 读取客户端消息charbuf[64]{};ssize_t nread(cfd,buf,sizeof(buf)-1);if(n-1){cerrread() failedendl;}elseif(n0){coutClient closed connectionendl;}else{buf[n]\0;// 确保字符串终止coutReceived: bufendl;}// 8. 发送回复消息constchar*msgHello from server;ssize_t sentwrite(cfd,msg,strlen(msg));if(sent-1){cerrwrite() failedendl;}// 9. 关闭连接close(cfd);close(fd);return0;}客户端#includearpa/inet.h#includecstring#includeiostream#includesys/socket.h#includeunistd.husing namespace std;intmain(){// 创建 TCP 套接字返回文件描述符intfdsocket(AF_INET,SOCK_STREAM,0);// 设置服务器地址结构体初始化为全 0sockaddr_in addr{};// 设置地址族为 IPv4addr.sin_familyAF_INET;// 设置服务器 IP 为本地回环地址addr.sin_addr.s_addrinet_addr(127.0.0.1);// 设置服务器端口 8888转为网络字节序addr.sin_porthtons(8888);// 连接到服务器connect(fd,(sockaddr*)addr,sizeof(addr));coutConnected to serverendl;// 向服务器发送消息constchar*msgHello from client;write(fd,msg,strlen(msg));coutSent: msgendl;// 读取服务器的回复消息charbuf[64]{};read(fd,buf,sizeof(buf));coutReceived: bufendl;// 关闭套接字连接close(fd);return0;}