Socket读取数据失败咨询:客户端二次读取阻塞原因排查
关于Socket两次写入但客户端仅收到一次的问题分析
这种问题我在调试TCP Socket程序时碰到过好几次,咱们一步步拆解可能的原因,再解答你关心的“write早于read”的疑问:
最常见的原因:TCP粘包问题
TCP是流式协议,它不会帮你区分“第一次发送”和“第二次发送”的边界。如果服务器两次write的间隔很短,或者数据量不大,内核很可能会把这两段数据合并成一个TCP段发送给客户端。这时候:
- 如果客户端第一次
read调用用了足够大的缓冲区,会一次性把两次write的数据都读走; - 你以为只收到了第一次的数据,实际上第二次的数据已经在客户端的缓冲区里了,只是你没处理这部分内容,导致第二次
read时因为没有新数据而阻塞。
客户端read调用的逻辑错误
这也是很常见的坑:
- 如果你固定了
read的字节数(比如每次只读第一次发送的100字节),但第二次发送的数据不足这个数,客户端会一直等待剩余字节到达,从而阻塞; - 另外,很多新手会忽略
read的返回值——read返回的是实际读取到的字节数,而不是你请求的字节数。如果没检查这个值,你可能会误以为只收到了第一次的数据,实际上已经把两次的数据都读进缓冲区了,只是没处理后面的部分。
服务器端write的隐性问题
虽然你说两次write都显示“成功”,但要注意:
write返回成功只是表示数据被写入了内核的发送缓冲区,不代表数据已经发送到客户端;- 有时候如果内核发送缓冲区已满,
write会返回部分字节(比如你要发200字节,只写入了150),如果你没处理这种情况,剩下的50字节就没发出去,客户端自然收不到第二次的完整数据。所以一定要检查write的返回值是否等于你要发送的字节数。
关于“服务器write早于客户端read”的疑问
这个大概率不是问题!TCP本身就是异步的,服务器先write的数据会存在客户端的接收缓冲区里,客户端后续的read完全可以读到这些数据。除非服务器在write后立刻关闭了Socket,并且客户端没处理FIN包(但这种情况客户端read会返回0,而不是阻塞),否则这个原因可以排除。
排查建议
- 在服务器端每次
write后,打印实际写入的字节数,确认是否和预期一致; - 在客户端每次
read后,打印返回的字节数和读到的完整内容,看看是不是第一次就读取了所有数据; - 用
tcpdump或者Wireshark抓包,直接观察TCP流里的数据,确认服务器是否真的发送了两次数据,客户端是否收到。
内容的提问来源于stack exchange,提问作者theMan
相关产品推荐
相关产品推荐

