如何从标头确定有效负载大小?
Posted
技术标签:
【中文标题】如何从标头确定有效负载大小?【英文标题】:How to determine payload size from header? 【发布时间】:2020-09-16 12:57:40 【问题描述】:我想从 A 侧发送具有正文大小的正文和标头。 在 B 面,在第一个 recv() 标头中确定有效负载的大小。第二个,recv() 主体。
我尝试使用 recv() 两次,但无法通过第二个 recv() 函数。
A面
struct CommandHeader_t
int BodySizeByte;
;
void Send()
const int BODY_SIZE_BYTE = 10;
CommandHeader_t* header_ptr = (CommandHeader_t*) malloc(sizeof(CommandHeader_t) + BODY_SIZE_BYTE);
header_ptr->BodySizeByte = BODY_SIZE_BYTE;
char* body_ptr = (char*) (header_ptr + sizeof(CommandHeader_t));
snprintf(body_ptr, BODY_SIZE_BYTE, "Hello World");
int sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
struct sockaddr_un addr = 0;
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, SENDING_SOCKET);
sendto(sock, header_ptr, sizeof(CommandHeader_t) + BODY_SIZE_BYTE, 0, (const struct sockaddr*)&addr, sizeof(addr));
close(sock);
B面
void Reveice()
// something
CommandHeader_t header;
char* body_ptr;
recv(sockfd, &header, sizeof(CommandHeader_t), 0);
body_ptr = (char*) malloc(header.BodySizeByte);
recv(sockfd, body_ptr, header.BodySizeByte, 0); // CANNOT recv anything
【问题讨论】:
看起来您发送了一个带有标题和内容的数据报。接收方收到了数据报,但是recv()
只表示了报头的大小。因此,数据报的其余部分被丢弃并丢弃。因此,在第二次接收中,没有汤适合你。
建议:不要忽略返回码。它们几乎总是包含重要信息,例如“我真正得到了多少字节的数据?”或“我得到什么了吗?”以及曾经流行的“嘿,我的插座还活着吗?”。
由于这是 UDP,您甚至没有提及,因此无需发送有效负载大小。 recv()
的返回值已经提供了。
【参考方案1】:
你的代码有一些错误:
在发送端,分配body_ptr
指针时,您没有正确执行指针运算。因为header_ptr
被声明为CommandHeader_t*
,所以执行(header_ptr + sizeof(CommandHeader_t))
将计算一个内存地址,该地址是sizeof(CommandHeader_t)
数量的CommandHeader_t
元素超过header_ptr
指向的地址。那不是你想要的。相反,您需要计算一个地址,该地址是 sizeof(CommandHeader_t)
的 char
s 数量超过 header_ptr
地址。
所以,你需要改变这个:
char* body_ptr = (char*) (header_ptr + sizeof(CommandHeader_t));
改为:
char* body_ptr = ((char*) header_ptr) + sizeof(CommandHeader_t);
更简单的处理方法是在CommandHeader_t
中添加一个char[1]
成员,然后在malloc()
'ing 时减1,例如:
#pragma pack(push, 1) // or equivalent
struct CommandHeader_t
int BodySizeByte;
char data[1];
;
#pragma pack(pop) // or equivalent
CommandHeader_t* header_ptr = (CommandHeader_t*) malloc(offsetof(CommandHeader_t, data) + BODY_SIZE_BYTE);
header_ptr->BodySizeByte = BODY_SIZE_BYTE;
char* body_ptr = header_ptr->data;
snprintf(body_ptr, BODY_SIZE_BYTE, "Hello World");
另外,由于您在发送端使用SOCK_DGRAM
,sendto()
是面向消息的,在 1 条消息中发送整个数据。但是您的接收代码是编写的,就好像它使用的是面向流的套接字一样。不要像这样不匹配套接字类型。如果要多次调用recv()
,请在两侧使用面向流的套接字。否则,在两边都使用面向消息的套接字,然后让接收者分配一个足够大的缓冲区以接收 1 recvfrom()
中的整个消息(您可以使用ioctl(FIONREAD)
来确定下一条待处理消息的大小),然后根据需要解析该消息的内容。
此外,您的接收器正在泄漏它使用malloc()
分配的body_ptr
缓冲区。
【讨论】:
以上是关于如何从标头确定有效负载大小?的主要内容,如果未能解决你的问题,请参考以下文章
可有效存储在 tar 存档标头的大小字段中的最大无符号整数是多少