C错误从流式套接字读取数据包

Posted

技术标签:

【中文标题】C错误从流式套接字读取数据包【英文标题】:C error reading packet from streaming socket 【发布时间】:2013-02-08 21:21:30 【问题描述】:

我只是在 C 中使用流式套接字,但在读取从服务器应用程序返回的数据包时遇到问题。下面的代码显示了在客户端和服务器端使用的结构。

struct packet

    uint16_t f1;
    uint16_t f2;
    uint32_t f3;
    uint16_t pf1;
    uint32_t pf2;
;

发送服务器端:

char buffer[14];
struct packet myPacket;

myPacket.f1 = 2321;
myPacket.f2 = 4423;
myPacket.f3 = 2134;
myPacket.pf1 = 765;
myPacket.pf2 = 9867;

htonPacket(myPacket, buffer);

将数据打包到缓冲区的函数。

void htonPacket(struct packet h, char buffer[14]) 
    uint16_t u16;
    uint32_t u32;

    u16 = htons(h.f1);
    memcpy(buffer+0, &u16, 2);

    u16 = htons(h.f2);
    memcpy(buffer+2, &u16, 2);

    u32 = htonl(h.f3);
    memcpy(buffer+4, &u32, 4);

    u16 = htons(h.pf1);
    memcpy(buffer+8, &u16, 2);

    u32 = htonl(h.pf2);
    memcpy(buffer+10, &u32, 4);

解包打印客户端:

void ntohPacket(struct packet* h, char buffer[14]) 
    uint16_t u16;
    uint32_t u32;

    memcpy(&u16, buffer+0, 2);
    h->f1 = ntohs(u16);

    memcpy(&u16, buffer+2, 2);
    h->f2 = ntohs(u16);

    memcpy(&u32, buffer+4, 4);
    h->f3 = ntohl(u32);

    memcpy(&u16, buffer+6, 2);
    h->pf1 = ntohs(u16);

    memcpy(&u32, buffer+8, 4);
    h->pf2 = ntohl(u32);

打印解压后的数据:

printf("myPacket.f1: %d\n", myPacket.f1);
printf("myPacket.f2: %d\n", myPacket.f2);
printf("myPacket.f3: %d\n", myPacket.f3);
printf("myPacket.pf1: %d\n", myPacket.pf1);
printf("myPacket.pf2: %d\n", myPacket.pf2);

当我打印这些值时,很明显我在寻址或写入错误的内存位置时遇到了一些问题,但我似乎找不到错误。

myPacket.f1: 2321
myPacket.f2: 4423
myPacket.f3: 2134
myPacket.pf1: 2134
myPacket.pf2: 50135040

【问题讨论】:

为什么所有的舞蹈都是从一个结构中复制东西到一个变量中,然后调整字节序和 memcpy?你可以一口气做dst->f1 = htons(src->f1)。让structs 处理事情要容易得多,而不是胡乱处理单个字节(当然,您必须小心编译器不会偷偷填充)。我认为以这种方式重做代码将解决您的问题。 我正在学习,我只是在扩展我在数据包中找到的一个示例。感谢您的建议。 @vonbrand:将其发布为答案,您将获得我的 + 投票;) 【参考方案1】:

好吧,您在 memcpy 操作中使用了不同的偏移量,所以您当然会得到垃圾......

memcpy(buffer+0, &u16, 2);
memcpy(buffer+2, &u16, 2);
memcpy(buffer+4, &u32, 4);
memcpy(buffer+8, &u16, 2);
memcpy(buffer+10, &u32, 4);

对比

memcpy(&u16, buffer+0, 2);
memcpy(&u16, buffer+2, 2);
memcpy(&u32, buffer+4, 4);
memcpy(&u16, buffer+6, 2);
memcpy(&u32, buffer+8, 4);

ntohPacket 中的最后几行应该是

memcpy(&u16, buffer+8, 2);
h->pf1 = ntohs(u16);

memcpy(&u32, buffer+10, 4);
h->pf2 = ntohl(u32);

【讨论】:

哦,谢谢。然而,在更正之后,出现了更有趣的事情。现在最后一个值与我的预期略有不同。 myPacket.pf2: 9728 当我发送 9867 时。 我会按照@vonbrand 的建议(在他的评论中)做。维持所有这些指标,总有一天会给你带来难以言喻的痛苦。【参考方案2】:

您的 memcpy 偏移量错误。固定:

memcpy(&u16, buffer+0, 2);
h->f1 = ntohs(u16);

memcpy(&u16, buffer+2, 2);
h->f2 = ntohs(u16);

memcpy(&u32, buffer+4, 4);
h->f3 = ntohl(u32);

memcpy(&u16, buffer+8, 2);  <-- here
h->pf1 = ntohs(u16);

memcpy(&u32, buffer+10, 4);  <-- here
h->pf2 = ntohl(u32);

【讨论】:

【参考方案3】:

为什么所有的舞蹈都需要从一个结构复制东西到一个变量中,然后调整字节顺序和 memcpy?你可以一口气做dst-&gt;f1 = htons(src-&gt;f1)。让structs 处理东西要容易得多,而不是胡乱处理单个字节(当然,你必须小心编译器不会偷偷填充)。我认为以这种方式重做您的代码将解决您的问题。

【讨论】:

以上是关于C错误从流式套接字读取数据包的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE数据连接报错无法从套接字读取更多的数据怎么解决

C# Begin/EndReceive - 我如何读取大数据?

使用 BinaryReader/Writer 的 C# Socket 从读取器获取错误数据

C:你如何通过套接字读取和解包消息?

没有更多数据可以从套接字错误中读取

在以下情况下从套接字读取数据已损坏?