我想接收多个分块发送的请求。为了做到这一点,我正在使用带有recv的TCP套接字。我遍历recv如下:
while ((total_recv < MAX_HEADER) && (received = recv(client, req_buffer, CHUNK, 0)) > 0) {
total_recv += received;
if (strstr(req_buffer, delimiter) != NULL)
break;
}
我的目标是在收到由定界符标记的标头后停止接收。我不能保证存在定界符,因此如果total_recv大于或等于最大已知标头大小,则会中断循环。
我不喜欢这样。令我困扰的是,我可以收到没有小于最大报头大小的没有分隔符的数据包。在这种情况下,我不得不假设recv将继续增加total_recv直到循环中断。通过读取套接字API,我知道recv将返回读入缓冲区的字节数,如果错误则返回-1,如果连接已关闭则返回0。
是否有更好的方法可以在不依赖超时的情况下循环播放recv?打开连接但发送方或接收方未传输数据时,send()和recv()到底返回什么?
答案 0 :(得分:2)
如果套接字处于阻止模式(默认),recv()
将等待直到有可用数据返回。解决此问题的唯一方法是超时。最简单的方法是使用select()
或epoll()
。
如果套接字处于非阻塞模式,则recv()
将在没有可用空间时立即返回-1
,并且errno
将被设置为EWOULDBLOCK
。您仍然需要使用某种超时方法,因为这可能仅是由于在接收到所有已发送的数据之前调用recv()
太早了。
超时是一种非常脆弱的机制,因为总有可能出现暂时性的网络错误,其持续时间超过超时的时间,并且您会错误地将中断之前的数据视为完整的数据。
也许您可以重新设计协议以更好地处理此问题。让发送者发送带有消息中字节数的前缀,而不是读取分隔符,然后调用recv()
直到得到那么多字节。
答案 1 :(得分:1)
是的,您的代码需要改进。
您需要循环的原因是recv
可能返回的值少于完整的标头,即使在标头中稍后出现定界符也是如此。因此,您必须返回并阅读更多内容。
您的代码中存在一个问题,即第二次调用recv
,它将第二次读取到缓冲区的开头。
您需要测试EOF。
如果没有数据发送,recv
将等待直到有数据发送。
如有必要,它将永远等待,
但是如果套接字关闭,它将返回不成功。