我如何知道在第一次调用 recv 后读取缓冲区是否为空?
即使是第一次(在接受客户端之后),如果客户端连接丢失,recv 也会阻塞并失败。您必须:
- 使用
select
或poll
(BSD 套接字)或某些特定于操作系统的等效项,它可以告诉您特定套接字描述符上是否有可用数据(以及异常条件和可以写入更多输出的缓冲区空间)
- 您可以将套接字设置为非阻塞,这样
recv
只会返回立即可用的内容(可能没有)
- 您可以创建一个线程,您可以负担得起阻塞
recv
数据,知道其他线程将执行您关心的其他工作以继续
我如何知道我读入了 recv_buffer 的字节数?我不能使用 strlen 因为我收到的消息可能包含空字节。
recv()
返回读取的字节数,或 -1 错误。
请注意,TCP 是一种字节流协议,这意味着您只能保证能够以正确的顺序从中读取和写入字节,但不能保证保留消息边界。因此,即使发送方对他们的套接字进行了一次大的单次写入,它也可以在途中被分段并以几个较小的块到达,或者可以通过一个/合并和检索几个较小的send()
/ s 。write()
recv()
read()
出于这个原因,请确保您循环调用recv
,直到您获得所需的所有数据(即您可以处理的完整逻辑消息)或出现错误。您应该准备/能够处理send
从您的客户端获取部分/所有后续 s(如果您没有协议,其中每一方仅在从另一方获得完整消息后发送,并且不使用具有消息长度的标头) . 请注意,对消息头(带有长度)进行recvs,然后正文可能会导致更多的调用recv()
,从而对性能产生潜在的不利影响。
这些可靠性问题经常被忽略。在单个主机、可靠且快速的 LAN、涉及较少的路由器和交换机以及较少或非并发消息的情况下,它们的表现较少。然后它们可能会在负载和更复杂的网络上中断。