
文章目录客户端服务端需要修正的地方1. 服务端没有处理“客户端断开”的逻辑最严重2. 客户端发送速度过快刷屏3. 客户端没有检查 read() 的返回值✅ 修正后的服务端代码✅ 修正后的客户端代码 修正问题清单客户端#includearpa/inet.h#includecstring#includeiostream#includesys/socket.h#includeunistd.husingnamespacestd;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;while(1){// 向服务器发送消息constchar*msgHello from client;write(fd,msg,strlen(msg));coutSent: msgendl;// 读取服务器的回复消息charbuf[64]{};read(fd,buf,sizeof(buf));coutReceived: bufendl;}// 关闭套接字连接close(fd);return0;}服务端#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);// sleep(50); //调试代码使用便于调试的使用使用 ss -lntp// 查看已经连接的客户端信息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;while(1){// 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;}服务端在accept()之后套了一个while(1)意味着处理完一条消息后会继续等待下一条而不会关闭连接。客户端在connect()之后套了一个while(1)意味着发完一条并收到回复后会立即发送下一条。这样双方就形成了一个“客户端发送 - 服务端接收并回复 - 客户端接收并再发送”的无限循环需要修正的地方虽然功能实现了但你的代码中存在几个严重的逻辑隐患如果不修复程序可能会崩溃或占满 CPU1. 服务端没有处理“客户端断开”的逻辑最严重当客户端主动关闭连接或崩溃时服务端的read(cfd, ...)会返回0表示对方关闭。但你的代码里n 0时只是打印了语句并没有break跳出循环。这会导致服务端陷入死循环疯狂调用read()每次都返回0导致 CPU 占用飙到 100%。建议修改cppif (n -1) {cerr “read() failed” endl;break; // 出错退出} else if (n 0) {cout “Client closed connection” endl;break; // 对方断开退出循环} else {// … 正常处理数据}2. 客户端发送速度过快刷屏客户端在while(1)中没有任何延时会疯狂地往内核缓冲区塞数据。如果服务端处理稍慢客户端的write()最终会被阻塞。虽然不会报错但控制台会疯狂刷屏不方便观察。建议修改在客户端的循环末尾加个短暂延时比如sleep(1)或usleep(500000)让观察更清晰。3. 客户端没有检查read()的返回值如果服务端崩溃或主动关闭客户端的read()会返回0或-1但你的代码没有判断会继续打印空数据或执行错误逻辑。✅ 修正后的服务端代码#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);// sleep(50); // 调试用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. 循环通信while(1){charbuf[64]{};ssize_t nread(cfd,buf,sizeof(buf)-1);if(n-1){cerrread() failedendl;break;// 读取出错退出循环}elseif(n0){coutClient closed connectionendl;break;// 客户端断开退出循环}else{buf[n]\0;coutReceived: bufendl;// 发送回复constchar*msgHello from server;ssize_t sentwrite(cfd,msg,strlen(msg));if(sent-1){cerrwrite() failedendl;break;// 写入失败退出循环}}}// 8. 关闭连接close(cfd);close(fd);return0;}✅ 修正后的客户端代码#includearpa/inet.h#includecstring#includeiostream#includesys/socket.h#includeunistd.husingnamespacestd;intmain(){// 创建 TCP 套接字intfdsocket(AF_INET,SOCK_STREAM,0);if(fd-1){cerrsocket() failedendl;return-1;}// 设置服务器地址sockaddr_in addr{};addr.sin_familyAF_INET;addr.sin_addr.s_addrinet_addr(127.0.0.1);addr.sin_porthtons(8888);// 连接到服务器if(connect(fd,(sockaddr*)addr,sizeof(addr))-1){cerrconnect() failedendl;close(fd);return-1;}coutConnected to serverendl;// 循环通信intcount0;// 添加计数器避免无限发送可选while(1){// 发送消息constchar*msgHello from client;ssize_t sentwrite(fd,msg,strlen(msg));if(sent-1){cerrwrite() failedendl;break;}coutSent: msgendl;// 读取回复charbuf[64]{};ssize_t nread(fd,buf,sizeof(buf)-1);if(n-1){cerrread() failedendl;break;}elseif(n0){coutServer closed connectionendl;break;}else{buf[n]\0;coutReceived: bufendl;}// 适当延时避免刷屏单位秒sleep(1);// 可选发送一定次数后退出避免无限循环// if (count 10) break;}close(fd);return0;} 修正问题清单问题原代码行为修正内容影响服务端未处理客户端断开read()返回0时仅打印不退出循环导致死循环占满 CPU在n 0时添加break避免空转正常退出服务端未处理读取错误read()返回-1时仅打印继续循环添加break退出避免在错误状态下继续服务端未处理写入错误write()失败时仅打印继续循环添加break退出及时发现问题并退出客户端未检查connect()返回值直接连接未判断失败添加if判断并退出避免后续操作无效客户端未检查write()返回值未判断发送是否成功添加if判断并退出检测网络异常客户端未检查read()返回值直接读取未判断对方关闭或错误添加n -1和n 0处理正确处理服务端断开客户端发送过快无延时疯狂发送导致刷屏在循环末尾添加sleep(1)控制节奏便于观察