在Receiver中,我有
recvfd=accept(sockfd,&other_side,&len);
while(1)
{
recv(recvfd,buf,MAX_BYTES-1,0);
buf[MAX_BYTES]='\0';
printf("\n Number %d contents :%s\n",counter,buf);
counter++;
}
在发件人中,我有
send(sockfd,mesg,(size_t)length,0);
send(sockfd,mesg,(size_t)length,0);
send(sockfd,mesg,(size_t)length,0);
MAX_BYTES是1024,mesg的长度是15.目前,它只调用recv一次。我想为每个相应的发送调用recv函数三次。我如何实现它?
答案 0 :(得分:3)
要通过字节流协议发送离散消息,您必须将消息编码为某种框架语言。网络可以将协议划分为任意大小的数据包,因此接收不会以任何方式与您的消息相关联。接收器必须实现识别帧的状态机。
一个简单的成帧协议是有一些长度字段(比如两个八位字节:16位,最大帧长度为65535字节)。长度字段后面跟着那么多字节。
您甚至不能假设长度字段本身一次全部收到。您可能要求两个字节,但recv
只能返回一个字节。从套接字收到的第一条消息不会发生这种情况,因为网络(或本地IPC管道)段永远不会只有一个字节长。但是在流中间的某个地方,16位长度字段的第一个字节可能会落在一个网络帧的最后位置。
处理此问题的一种简单方法是使用缓冲的I / O库而不是原始操作系统文件句柄。在POSIX环境中,您可以使用打开的套接字句柄,并使用fdopen
函数将其与FILE *
流关联。然后,您可以使用getc
和fread
等函数来简化输入处理(稍微)。
如果无法接受带内成帧,则必须使用支持成帧的协议,即数据报类型套接字。这样做的主要缺点是IP上使用的基于主数据报的协议是UDP,而UDP是不可靠的。这会在您的应用程序中带来很多复杂性,以处理乱序和丢帧。帧的大小也受最大IP数据报大小的限制,大小约为64千字节,包括所有协议头。
大型UDP数据报会碎片化,如果网络中存在不可靠性,则会增加更大的不可靠性:如果丢失了任何IP片段,则整个数据包都会丢失。所有这些都必须重新传输;没有办法只重复丢失的片段。 TCP协议执行“路径MTU发现”以调整其段大小,以避免IP分段,并且TCP具有选择性重传以恢复丢失的段。
答案 1 :(得分:0)
我敢打赌你使用SOCK_STREAM创建了一个TCP套接字,这会导致在第一次recv
调用期间将三条消息读入缓冲区。如果要逐个读取消息,请使用SOCK_DGRAM创建UPD套接字,或者开发某种类型的消息格式,以便在消息到达流时解析消息(假设消息的长度不一定是固定的) )。
答案 2 :(得分:0)
简而言之:是,它正在阻止。但不是你想的那样。
recv()
阻止,直到任何数据可读。但你事先并不知道它的大小。
在您的方案中,您可以执行以下操作:
select()
并将要读取的套接字放入READ FD集select()
返回正数时,您的套接字已准备好要读取数据length
个字节:recv(recvfd, buf, MAX_BYTES-1, MSG_PEEK)
,MSG_PEEK
参见length
或查看MSDN,他们也有{/ li>
length
可用,则返回并且不执行任何操作length
可用,请阅读length
并返回(如果有超过select()
,我们将继续执行步骤2,因为新的READ事件将通过以下方式发出{{1}} 答案 3 :(得分:0)
首先以固定格式发送length
,以length
的大小(以字节为单位)传输此length
,然后使recv()
循环直到{已收到{1}}个字节。
注意事实(正如其他答案已经提到的那样),收到的块的大小和数量不一定需要与发送的相同。只接收的所有字节总和应与发送的所有字节总和相同。
阅读length
和recv
的手册页。特别是阅读有关这些功能 RETURN 的部分。
答案 4 :(得分:-3)
recv
将阻塞,直到填满整个缓冲区,或者套接字关闭。
如果您想阅读length
个字节并返回,那么您只能向recv
传递一个大小为length
的缓冲区。
您可以使用select
来确定是否
这可以避免recv
阻止。
修改强>
重新阅读文档后,可能会出现以下情况:自length + length + length < MAX_BYTES - 1
以来,您的三条“消息”可能会被一次性读取。
如果永远不会返回recv
,则另一种可能性是您可能需要flush
来自发件人方的套接字。数据可能在缓冲区中等待实际发送到接收方。