是否可以在更高级语言中查看数据报包?

时间:2011-10-28 11:46:37

标签: c udp datagram

我目前正在尝试将处理数据报(udp)数据包的c程序移植到某种更高级别的语言。由于数据包的大小可以变化,因此它们以一个表示其大小的整数开头。在c中,我使用MSG_PEEK标志调用recv以仅首先接收该值,然后分配一个拟合缓冲区并读取其余的数据包。代码(简化)如下:

// Simplified message format.
struct message {
    int length;
    char[] text;
}
struct message *m = malloc (sizeof(int));

// Read out in just length.
recv (sock, m, sizeof(int), MSG_WAITALL | MSG_PEEK);
int txtlen = ntohl (m->length) * sizeof(char);
int msglen = sizeof(int) + txtlen;

// Read complete packet.
m = realloc (m, msglen);
read (sock, m, msglen);
m->text[txtlen] = '\0';

// Show result.
printf("%s\n", &m->text);

我想避免看似普遍的做法是分配一个巨大的缓冲区,并希望没有更大的数据包到达。那么就像在python或java等高级语言中窥视数据报或确定其完整长度一样?

3 个答案:

答案 0 :(得分:1)

我想避免看似普遍的做法,即分配一个巨大的缓冲区,并希望数据包不会变得更大。

不确定你的意思。 UDP数据包一次到达,因此初始整数会告诉您缓冲区应该有多大;它到来后不会“增长”。

由于您附加了空字符,因此需要在长度计算中考虑该字符:

int msglen = sizeof(int) + txtlen + 1;

使用realloc()时要小心:

m = realloc (m, msglen);

如果realloc失败,则会将m设置为空。这意味着你将失去对最初分配给它的内存的唯一引用,因此你永远无法free()它。尝试这样的事情:

void *tmp = realloc(m, msglen)
if (tmp == null) {
  // handle the error
}
m = tmp;

当您打印数据时,m->text会计算出第一个字符的地址,因此您可以使用

printf("%s\n", m->text);

或者,您可以使用固定大小定义结构,如

struct message {
  int length;
  char *text;
}

然后您可以使用malloc()分配(仅)您的文本缓冲区:

struct message m;
recv(sock, &m.length, sizeof(int), MSG_WAITALL | MSG_PEEK);
m.text = malloc(m.length + 1); // +1 for the null that you'll append
read(sock, m.text, m.length);
m.text(m.length) = '\0';

printf("%s\n", m.text);
free(m.text);

祝你的项目好运 - 网络编程始终是一种学习经历!

答案 1 :(得分:0)

为什么不这样做?

message = (struct message *)malloc(sizeof(struct message));
read(sock, &message->length, sizeof(int);
message->length = ntohl(message->length);
message->text = (char *)malloc(message->length + 1);
read(sock, message->text, message->length);
message->text[message->length] = 0;

答案 2 :(得分:0)

UDP datagrams限制为64K,然后ethernet frames为1500字节(除非您的网络使用jumbo frames,最多可能为9000字节)。协议设计者通常会尝试避免IP fragmentation,因此很可能您的传入数据包很小,即少于1500字节。

我将从1472的静态缓冲区开始(1500个以太网帧长度--20个字节的IP报头 - 8个字节的UDP报头)。如果你必须处理一些任意协议 - 最高可达64K。如果您负担不起 - 使用MSG_PEEK收集实际尺寸,找到一些方便的平均值,并使用malloc(3)设置后备计划。