【问题标题】:constructing and parsing network packet构造和解析网络数据包
【发布时间】:2012-04-24 15:45:23
【问题描述】:

我有以下数据包格式:

   1B       4B      1B    1B    string   2 bytes    1B      string  
+------+----------+---+--------+---~~--+---------+--------+---~~---+
| type | lifetime | 2 | length | Name  | Counter | length |  Data  |
+------+----------+---+--------+---~~--+---------+--------+---~~---+

typedef struct pkt_data {
    u_char pkt_type;
    u_int lifetime;
    u_char type;
    u_char len_name;
    u_char name[100];
    u_short counter;
    u_char len_data;
    u_char data[200];
}__attribute__((__packed__)) Data;

下面是构造和解析数据包的代码:

int buildDataPacket(u_int _lifetime, u_char* _name, u_short _counter, u_char* _data, u_char* _dataPacket) {
    Data *ndata=NULL;
    u_char *ptr;

    memset(_dataPacket, 0, 512);

    ndata = (Data *) _dataPacket;
    ndata->pkt_type = 2;
    ndata->lifetime = htonl(_lifetime);
    ndata->type = 2;
    ndata->len_name = strlen(_name);

    ptr = (u_char *)ndata + (3 * sizeof(u_char)) + sizeof(u_int);
    strncpy((char *)ptr, (char *)_name, strlen(_name));

    u_short counter = htons(_counter);
    u_char datalen = strlen(_data);

    ptr = ptr + strlen(_name);
    memcpy(ptr, &counter, sizeof(u_short));
    ptr = ptr + sizeof(u_short);
    memcpy(ptr, &datalen, sizeof(u_char));
    ptr = ptr + sizeof(u_char);
    strncpy((char *)ptr, (char *)_data, strlen(_data));
    ptr = ptr + strlen(_data);

    return (ptr - (u_char *)_dataPacket);
}

int processDataPacket(u_char* _dataPacket, u_short _pktLen)
{
    if (!_dataPacket || !_pktLen) {
            return -1;
    }

    Data *dataPkt;
    dataPkt = (Data *)_dataPacket;

    printf("Lifetime: %d\n", ntohl(dataPkt->lifetime));
    printf("Name: %s\n", dataPkt->name);
    printf("Counter: %d\n", dataPkt->counter);
    printf("Data: %s\n", dataPkt->data);

    return 0;
}

当我在wireshark中嗅探数据包时,发现数据包的构造是按照格式来的。但是“counter”和“len_data”的值是零,即使我相应地设置了它们。此外,当我收到数据包时,完整的数据包不会存储在缓冲区中。

rval=recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT, (struct sockaddr *) &dest_sin, &socklen);

buf[rval]=0;
fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);

'rval' 返回正确的总字节数,但 'buf' 在“name”之后终止。 strlen(buf) 仅返回数据包的长度,直到名称为止。所以“数据”在 processDataPacket 中是空的。请指导我如何构造和解析这个数据包。

【问题讨论】:

    标签: c sockets network-programming


    【解决方案1】:
    ptr = ptr + strlen(_name);
    memcpy(ptr, &counter, sizeof(u_short));
    

    这是错误的。当您应该精确地推进指针100 时,您只是推进指针strlen(_name) 的位置,因为_nameu_char name[100]

    旁注:

    • u_int lifetime; 不保证为 4 个字节。为此使用uint32_tu_short 也是如此(使用 uint16_t

    strlen(buf) 返回包的长度

    由于数据包不只是一个大字符串(它还包含非文本数据,例如u_int lifetime),因此无法使用strlen,它将在第一个0 字节处停止。

    【讨论】:

    • 好的,谢谢您的回复。有没有办法可以根据namedata 字符串的长度将数据包长度更改为可变,而不是将长度固定为100 和200。我尝试使用 char* 而不是 char[100],但是在构造数据包时出现分段错误。另一个问题是,当我执行 recvfrom 时,buf 不会显示整个数据包,即使 rval 返回整个数据包的总字节数。我认为由于name 字符串后的零,buf 被终止,因此仅显示数据包直到name 结束。我该如何解决这个问题?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    • 2011-01-23
    • 1970-01-01
    • 2019-07-05
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多