在接收器中,我有
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++;
}
Run Code Online (Sandbox Code Playgroud)
在 Sender ,我有
send(sockfd,mesg,(size_t)length,0);
send(sockfd,mesg,(size_t)length,0);
send(sockfd,mesg,(size_t)length,0);
Run Code Online (Sandbox Code Playgroud)
MAX_BYTES 为 1024,消息长度为 15。目前,它只调用一次 recv。我希望为每个相应的发送调用 recv 函数三次。我如何实现它?
简而言之:是的,它是阻塞的。但不是你想的那样。
recv()阻塞直到任何数据可读。但你事先并不知道尺寸。
在您的场景中,您可以执行以下操作:
select()并将要读取的套接字放入 READ FD 集中select()返回正数时,您的套接字已准备好读取数据length从套接字接收字节:recv(recvfd, buf, MAX_BYTES-1, MSG_PEEK),查看man recv(2)参数MSG_PEEK或查看 MSDN,他们也有它length可用数量,则返回并且不执行任何操作length可用的,则读取length并返回(如果有超过length可用的,我们将继续步骤 2,因为新的 READ 事件将由select()要通过字节流协议发送离散消息,您必须将消息编码为某种帧语言。网络可以将协议分成任意大小的数据包,因此接收的消息与您的消息没有任何关联。接收器必须实现一个识别帧的状态机。
一个简单的成帧协议是有一些长度字段(比如两个八位字节:16 位,最大帧长度为 65535 字节)。长度字段后跟正是那么多字节。
您甚至不能假设长度字段本身是一次性收到的。您可能会要求两个字节,但recv可以只返回一个。对于从套接字接收到的第一条消息,这不会发生,因为网络(或本地 IPC 管道,就此而言)段永远不会只有一个字节长。但是在流中间的某个地方,16 位长度字段的第一个字节可能会落在一个网络帧的最后一个位置。
解决这个问题的一个简单方法是使用缓冲 I/O 库而不是原始操作系统文件句柄。在 POSIX 环境中,您可以获取一个打开的套接字句柄,并使用该fdopen函数将其与FILE *流相关联。然后你可以使用像getc和fread这样的函数来简化输入处理(有点)。
如果带内成帧是不可接受的,那么您必须使用支持成帧的协议,即数据报类型套接字。这样做的主要缺点是 IP 上使用的主要基于数据报的协议是 UDP,而 UDP 不可靠。这给您的应用程序带来了很多复杂性,以处理无序和丢失的帧。帧的大小还受到最大 IP 数据报大小的限制,该数据报大小约为 64 KB,包括所有协议标头。
大的 UDP 数据报会被分段,如果网络中存在不可靠性,这会增加更大的不可靠性:如果任何 IP 分段丢失,整个数据包都会丢失。所有这些都必须重新传输;没有办法只获得丢失的片段的重复。TCP 协议执行“路径 MTU 发现”以调整其分段大小以避免 IP 分片,并且 TCP 具有选择性重传以恢复丢失的分段。
Mat*_*ser -4
recv将阻塞直到整个缓冲区被填满,或者套接字被关闭。
如果您想读取length字节并返回,则必须仅传递给recvsize 的缓冲区length。
您可以使用select来确定是否
这样可以避免recv阻塞。
编辑:
重新阅读文档后,以下情况可能是正确的:自 以来,您的三个“消息”可能会被一次性读取length + length + length < MAX_BYTES - 1。
另一种可能性(如果recv永远不会返回)是您可能需要flush从发送方访问您的套接字。数据可能在缓冲区中等待实际发送到接收器。
| 归档时间: |
|
| 查看次数: |
16405 次 |
| 最近记录: |