3

在接收器中,我有

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 函数。我如何实现它?

4

5 回答 5

5

要通过字节流协议发送离散消息,您必须将消息编码为某种框架语言。网络可以将协议分割成任意大小的数据包,因此接收到的信息不会以任何方式与您的消息相关联。接收器必须实现一个识别帧的状态机。

一个简单的成帧协议是有一些长度字段(比如两个八位字节:16 位,最大帧长度为 65535 字节)。长度字段后面紧跟着那么多字节。

您甚至不能假设长度字段本身是一次性收到的。您可能要求两个字节,但recv可能只返回一个。从套接字接收到的第一条消息不会发生这种情况,因为网络(或本地 IPC 管道,就此而言)段永远不会只有一个字节长。但是在流中间的某个地方,16 位长度字段的第一个字节可能会落在一个网络帧的最后一个位置。

处理这个问题的一个简单方法是使用缓冲 I/O 库而不是原始操作系统文件句柄。在 POSIX 环境中,您可以获取打开的套接字句柄,并使用该fdopen函数将其与FILE *流相关联。然后,您可以使用 和 之类的函数getcfread简化输入处理(在某种程度上)。

如果带内成帧不可接受,那么您必须使用支持成帧的协议,即数据报类型套接字。这样做的主要缺点是在 IP 上使用的主要基于数据报的协议是 UDP,而 UDP 是不可靠的。这会给您的应用程序带来很多复杂性,以处理乱序和丢失帧。帧的大小还受到最大 IP 数据报大小的限制,该大小约为 64 KB,包括所有协议头。

大的 UDP 数据报会被分段,如果网络中存在不可靠性,则会增加更大的不可靠性:如果任何 IP 分段丢失,则整个数据包都会丢失。所有这些都必须重新传输;没有办法只重复丢失的片段。TCP 协议执行“路径 MTU 发现”以调整其分段大小以避免 IP 分段,并且 TCP 具有选择性重传以恢复丢失的分段。

于 2013-06-07T19:16:58.680 回答
3

简而言之:的,它正在阻塞。但不是你想的那样。

recv()阻塞,直到任何数据可读。但是你事先不知道尺寸。

在您的场景中,您可以执行以下操作:

  1. 调用select()并将要读取的套接字放入 READ FD 集中
  2. select()返回正数时,您的套接字已准备好读取数据
  3. 然后,检查您是否可以length从套接字接收字节:
    recv(recvfd, buf, MAX_BYTES-1, MSG_PEEK),查看man recv(2)参数MSG_PEEK或查看 MSDN,他们也有
  4. 现在您知道有多少数据可用
  5. 如果不足length,则返回并且什么也不做
  6. 如果至少有length可用的,则读取length并返回(如果length可用的多,我们将继续第 2 步,因为新的 READ 事件将由select()
于 2013-06-07T19:08:55.040 回答
1

recv我敢打赌,您已经使用 SOCK_STREAM 创建了一个 TCP 套接字,这将导致在第一次调用期间将三个消息读入您的缓冲区。如果您想逐一读取消息,请使用 SOCK_DGRAM 创建一个 UPD 套接字,或开发某种类型的消息格式,允许您在消息到达流时解析消息(假设您的消息不总是固定长度)。

于 2013-06-07T18:37:14.093 回答
0

首先length以固定格式发送要接收的,关于length用于传输 this 的字节大小length,然后recv()循环直到length接收到字节。


请注意一个事实(正如其他答案已经提到的),接收到的块的大小和数量不一定需要与发送的相同。只有接收到的所有字节的总和应该与发送的所有字节的总和相同。

recv阅读和的手册页send。特别是阅读有关这些功能RETURN的部分。

于 2013-06-08T08:02:13.173 回答
-4

recv将阻塞直到整个缓冲区被填满或套接字关闭。

如果您想读取length字节并返回,那么您必须只传递给recvsize 的缓冲区length

您可以使用select来确定是否

  1. 有任何字节等待读取,
  2. 有多少字节等待读取,然后
  3. 只读取那些字节

这样可以避免recv阻塞。

编辑:

重新阅读文档后,以下情况可能是正确的:您的三个“消息”可能会从length + length + length < MAX_BYTES - 1.

另一种可能性(如果recv永远不会返回)是您可能需要flush从发送方访问您的套接字。数据可能在缓冲区中等待实际发送到接收器。

于 2013-06-07T18:37:03.960 回答