【问题标题】:I send a C structure through socket but can not get it right, always miss some bytes我通过套接字发送一个 C 结构但无法正确发送,总是错过一些字节
【发布时间】:2011-12-27 13:56:52
【问题描述】:

更新: 我添加了一个while 来获取剩余数据,问题解决了。谢谢你们。

while(res != rcvread->size + 4) {/* do not get full data */
    tmp = recv(connfd, (void *)rcvread + res, rcvread->size + 4 - res, 0);
    if(tmp == -1)
        printf("error:%s\n",(char *)strerror(errno));
    res+=tmp;
}

我想通过socket发送一个结构体mfsiowrite的返回值是37772,但是当我从其他程序中得到时,read的返回值是32768,真是奇怪。

这个结构的定义在这里

struct mfsio{
    size_t size;
    char buf[];
};

发送代码在这里

struct mfsio *sndread;
sndread = malloc(sizeof(struct mfsio) + rcvcmd->size);
res = pread(fd, &(sndread->buf), rcvcmd->size, rcvcmd->offset);
sndread->size = res;
res = write(connfd, sndread, sizeof(struct mfsio) + res);

接收码在这里

struct mfsio *rcvread;
rcvread = malloc(sizeof(struct mfsio) + size);
res = 0;    
res = read(connfd, rcvread, sizeof(struct mfsio) + size);

size等于rcvcmd->sizepread的res是32678,write的res是32772。 但read 的 res 是 32678。

怎么会发生这种事?我在这里做错了吗?

如果没有来自write 的输入,read 函数将等待一些数据并挂在那里

如果我使用循环来避免这样的问题,我怎样才能最终得到整个数据结构,我的意思是如果我循环读取,我会从套接字中获取剩余的字节,但是我该如何组合这些我收到的剪辑?

【问题讨论】:

  • 作为循环的一部分,您必须调整您读取的指针,将您之前读取的字节数添加到其中。不过,请确保您为此指针算术使用 char 指针。
  • 结构包装不可移植。您需要发送数据的序列化表示。
  • @kaizer.se 那么有没有 linux 上的 lib 可以做到这一点?我已经做了一些谷歌搜索,但没有找到。

标签: c linux sockets


【解决方案1】:

您需要在循环中进行读取和写入,直到读取/写入所有预期数据。对于读取,您必须读取直到它返回 0,表示没有其他可用的。或 -1 表示错误。

您最近的问题是您在结构指针中使用指针算术:

tmp = recv(connfd, rcvread + res, rcvread->size + 4 - res, 0);

在 C 中,当您进行指针运算时,您不是在使用字节,而是在使用对象的大小(例如 rvcread)。您应该定义一个char *,这是您将读取的字节位置,然后在您读取数据时更新它。

【讨论】:

  • 我想得到这个结构。如果我使用循环,那么我只能得到左边的字节,而不是整个结构。有办法解决吗?
  • 我认为你最好通过循环语句接收所有数据,就像上面厄普顿的回答一样。
  • 我添加这些代码来获取剩余数据,但它返回一个Bad address。 while(res != rcvread->size + 4){/* 没有得到完整的数据 */ tmp = recv(connfd, (void *)(rcvread + res), rcvread->size + 4 - res, 0); if(tmp == -1) printf("error:%s\n",(char *)strerror(errno)); res+=tmp; }`
  • 如果您仍然遇到问题,您可以编辑您的原始帖子以显示您现在使用的代码不起作用吗?我无法从评论中的代码中真正看到您在做什么,这太难阅读了。
  • 我扩展了我的答案,希望能解决您的问题。
【解决方案2】:

readwrite 对字节流进行操作。无法保证 read 读取的字节数与 write 写入的字节数一样多。使用 sendmsg 或将记录大小或记录分隔符放入流中。

【讨论】:

    【解决方案3】:

    弗朗西斯厄普顿的回答似乎是正确的,你当然应该听从他的建议。
    但我有另一个猜测,也许是问题所在。
    您没有展示如何在接收器中获得 size 的值。一个合理的方法是从套接字读取 4 个字节到大小。因此,如果您这样做,您已经读取了 4 个字节,并且在下一次读取时将减少 4 个字节。

    【讨论】:

    • 我只是从我的接收器中读取了最大可能的字节大小,并且数据等于或小于该大小。
    • @bxshi:这个概念行不通。发送方需要提供写入的实际大小,否则您无法在读取方确定要读取多少字节。
    【解决方案4】:

    recv() 上的标志 MSG_WAITALL 也可能很有趣,因为它基本上完成了整个操作

     while (!allDataReceived) {
       receiveMoreData();
     }
    

    给你的东西。

    但是,提示您应该发送带有“这是后面有多少字节”的标头的其他答案绝对是您应该听的。

    【讨论】:

      猜你喜欢
      • 2016-06-06
      • 2016-01-11
      • 1970-01-01
      • 1970-01-01
      • 2010-11-22
      • 2018-06-13
      • 2017-04-24
      相关资源
      最近更新 更多