簡體   English   中英

如何避免在發送數據包時填充

[英]how can I avoid padding in sending the packet

我想使用 write 系統調用發送一個數據包。 我創建了數據包,它的大小是 46 字節。 當我在wireshark的程序中發送數據包時,長度為60字節,填充14字節。 如何在沒有填充的情況下發送數據包。

我不能使用套接字命令。

struct x {
 bool is_active;
 bool is_owner;
 int fd1;
 int fd2;
 char pkt_hdr[sizeof(struct ether_header) + sizeof(struct ip)];
 struct interface *ifp;
 int fd_bufflen;
 struct ipaddr src;
 uint8_t ibuf[IP_MAXPACKET];
 int family;
 struct vrrp_vrouter *vr;
 struct list *addrs;
 bool ad;
 bool ga;
 bool nd;
 uint8_t priority;
 uint16_t ma_val;
 uint16_t sk_tm;
 uint16_t ma_val;
 struct ethaddr vmac;
  struct {
    int state;
  } fsm;

  struct {
    uint32_t ad_cnt;
    uint32_t ar_cnt;
    uint32_t g_cnt;
    uint32_t un_cnt;
    uint32_t t_cnt;
  } stats;

  struct thread *t_ti;
  struct thread *t_adti;
  struct thread *t_read;
  struct thread *t_write;
};
.
.
.
size_t buf_len = pktsz + sizeof r->pkt_hdr;
. 
.
.

/* Ethernet Header */
struct ether_header *ether_hdr = (struct ether_header *)buf;
.
.
.

/* IP Header */

struct ip *ip_hdr = (struct ip *) (ether_hdr + 1);
ip_hdr->ip_len = htons(buf_len - sizeof(struct ether_header));
ip_hdr->ip_src = r->src.ipaddr_v4;
ip_hdr->ip_sum = in_cksum(ip_hdr, sizeof(struct ip));

/* Payload */
memcpy((void *)(buf + sizeof r->pkt_hdr), (const void *)pkt, pktsz);

ssize_t sent = write(fd, buf, buf_len);
free(buf);

buf_len 是:46

pktsz : 12

r->pkt_hdr 的大小:34

長度為 46。

不幸的是, struct在存儲協議方面通常非常糟糕,因為它們的對齊和填充要求。 這意味着您不能在整個結構上使用memcpy等。 相反,必須在通過數據通信協議發送之前對struct進行序列化,以丟棄填充。

簡化示例:

typedef struct
{
  int i;
  char c;
} foo_t;

void foo_serialize (uint8_t dst[5], const foo_t* src)
{
  memcpy(dst, &src->i, 4);
  dst[4] = src->c;
}

在接收端需要一個類似的反序列化程序。

另一種選擇是使用非標准的#pragma pack(1)和類似方法“打包”結構。 這消除了填充,但填充是有原因的。 如果打包結構體,您的程序最終可能會讀取它未對齊,這可能導致代碼變慢或某些系統硬件異常。


但同時您還需要轉換為網絡字節序 Big endian 通常用於大多數數據協議。 重寫上面的例子,也可以從 little endian 轉換為 big endian:

void foo_serialize (uint8_t dst[5], const foo_t* src)
{
  dst[0] = ((uint32_t)src->i >> 24) & 0xFFu;
  dst[1] = ((uint32_t)src->i >> 16) & 0xFFu;
  dst[2] = ((uint32_t)src->i >>  8) & 0xFFu;
  dst[3] = ((uint32_t)src->i >>  0) & 0xFFu;
  dst[4] = src->c;
}

還有 POSIX htonl函數(主機字節序到網絡字節序,長格式),但由於該函數不能在 POSIX PC 計算機之外移植,它有點違背了它自己的目的。

打包可防止編譯器進行填充 - 這必須明確要求 - 在 GCC 下使用__attribute__((__packed__))

有關更多解釋,請訪問以下鏈接: https : //www.geeksforgeeks.org/structure-member-alignment-padding-and-data-packing/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM