You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ Socket编程select()实现错误 运行时出现服务器超时问题

原代码持续触发超时的核心问题
  • timeval的使用完全踩中Linux系统的API坑
    Linux实现的select()有个特殊副作用:返回时会直接修改传入的timeval结构体,把它的值更新成本次等待过程中剩余的时间。原代码把tv定义在循环外部,第一次循环走完5秒超时后,tv会被内核改成全0值,后面所有循环调用select()时,传入的超时时间都是0,根本不会等待任何数据,直接立刻返回超时状态。
    优化代码把tv的初始化挪到循环内部,每次循环都重新设置5秒超时,就是为了规避这个系统行为带来的问题。
  • 发出去的请求根本不符合协议格式,服务器不会回包
    原代码写的msg+"\r\n";是无意义的临时表达式——两个字符串相加的结果是个临时值,算完直接就被丢弃了,根本没有把\r\n拼到msg字符串里。不管是HTTP协议还是绝大多数TCP自定义协议,都要求消息以回车换行作为结束标识,服务器收到没有结束标识的残缺请求后,会一直等后续数据,不会返回任何响应,客户端等再久也收不到回包。
    另外原代码计算发送长度时多算了1个字节(msg.size()+1),把字符串结尾的\0也发了出去,进一步干扰服务器的请求解析。
  • recv()的调用逻辑完全错误
    当select()检测到socket可读后,原代码连续调用两次recv():第一次调用已经把内核缓冲区的所有数据读到了buf里,代码却直接把读到的内容扔掉,只判断返回值是不是小于0;第二次调用recv()时,内核缓冲区已经没有数据,要么返回-1报错,要么直接覆盖第一次读到的内容。同时代码用cout << buf按C字符串方式打印,遇到二进制数据里的\0就会提前截断,根本打不全收到的内容,也完全没处理recv()返回0(代表对方主动断开连接)的场景。
  • 循环逻辑从根上违背了select的设计初衷
    原代码把阻塞的getline(cin, msg)放在循环最开头,意味着程序每次上来就死等用户键盘输入,根本没法在等输入的间隙处理服务器主动推过来的socket数据,完全失去了select()同时监听stdin和网络socket的意义。

优化后的代码已经修复了上述所有问题:每次循环重新初始化超时时间、正确拼接消息后缀、通过循环分片保证send()把所有数据完整发完、单次recv()读取后用cout.write()按实际读到的字节数打印内容、增加断连分支处理,因此可以正常和各类TCP服务完成交互。

内容的提问来源于stack exchange,提问作者Cipher Visor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 02:06:03