【问题标题】:What's the pad to sockaddr_in for?sockaddr_in 的 pad 是做什么用的?
【发布时间】:2021-01-23 02:28:31
【问题描述】:

我是 C 和套接字编程的新手,仍在 sockaddr_in 结构中挣扎:

struct sockaddr_in {
    short            sin_family;   /* Protocol family (always AF_INET) */
    unsigned short   sin_port;     /* Port number in network byte order */
    struct in_addr   sin_addr;     /* IP address in network byte order */
    unsigned char    sin_zero[8];  /* Pad to sizeof(struct sockaddr) */
};

struct in_addr {
   uint32_t s_addr; /* Address in network byte order (big-endian) */
};

除了对齐要求,我不确定sin_zero是否需要,以下是我的假设,如果我错了,请纠正我:

假设1-因为sin_addr是32位的ipv4地址,如果我们需要一个ipv6地址,那么sin_zero的前4个字节将被分配并与sin_addr组合成一个64位的ipv6地址。

假设2-如果我的假设是正确的,那么我们需要指定套接字地址的长度,例如:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

是因为ipv6地址的可能性吗?所以如果使用ipv4,那么addrlen应该是8,如果使用ipv6,那么addrlen应该是12?

【问题讨论】:

  • 根据stackoverflow.com/questions/18609397/… sizeof(sockaddr_in6) > sizeof(sockaddr) == sizeof(sockaddr_in) sockaddr_in 需要至少与 sockaddr 一样大的原因是,您可以分配一个 sockaddr_in,然后在将其传递给库函数时将其转换为 sockaddr - 这有点像 C 的继承。sockaddr_in6 已经比 sockaddr 大,所以它不需要任何填充。

标签: c sockets


【解决方案1】:

有多个协议族。每个家族都有自己的地址结构。

示例:AF_INET 使用sockaddr_inAF_INET6 使用sockaddr_in6AF_UNIX 使用sockaddr_un 等。但sockaddr 是基本结构。在绑定/连接套接字时,所有这些结构都必须类型转换为 sockaddr

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

我们来看看sockaddr_insockaddr的结构:

struct sockaddr_in {
    short            sin_family;   /* Protocol family (always AF_INET) */
    unsigned short   sin_port;     /* Port number in network byte order */
    struct in_addr   sin_addr;     /* IP address in network byte order */
    unsigned char    sin_zero[8];  /* Pad to sizeof(struct sockaddr) */
};


struct in_addr {
   uint32_t s_addr; /* Address in network byte order (big-endian) */
};

sockaddr的结构是:

struct sockaddr 
{
    sa_family_t sa_family;
    char        sa_data[14];
}

查看sockaddr_insockaddr这两个结构中元素的大小。

两个结构中的第一个元素相同,占用相同的内存。

sin_port --> 2 个字节
sin_addr --> 4 个字节
sin_zero[8] --> 8 个字节
总计 = 14 字节(等于 sa_data[14] 的大小)

我们添加填充字节以使其结构大小相等。

参考:
https://man7.org/linux/man-pages/man2/bind.2.html
https://man7.org/linux/man-pages/man2/connect.2.html

【讨论】:

  • 感谢您的回答。但是,如果sockaddr_insockaddr 的大小相同,为什么我们需要指定长度addrlenbind 函数呢?
  • @amjad 看到这个答案:stackoverflow.com/questions/30251960/…
  • @amjad 其他类型的地址结构与sockaddr 的大小不同,例如sockaddr_in6sockaddr_un 要大得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-31
  • 2023-04-07
  • 2011-08-24
  • 2023-04-03
  • 2014-03-04
  • 2012-05-19
  • 2011-10-25
相关资源
最近更新 更多