套接字编程 (sys/socket.h)

Socket Programming (sys/socket.h)

查看定义的通用套接字结构 sys/socket.h 规范,它列出:

sa_family_t   sa_family       address family
char          sa_data[]       socket address (variable-length data)

在我的 linux 机器上查看位于 /usr/includes/sys/socket.h 的实际头文件,其定义如下。

 struct osockaddr
      {
        unsigned short int sa_family;
        unsigned char sa_data[14];
      };

现在我知道如果我包含 netinet/in.h 它将定义一个 sockaddr_in 结构并且因为我正在使用 AF_INET 它会使得自从使用这个...

struct sockaddr_in {
   short int            sin_family;
   unsigned short int   sin_port;
   struct in_addr       sin_addr;
   unsigned char        sin_zero[8];
};

但是,当我可以简单地使用通用 osockaddr 结构时,我觉得没有必要 #include 另一个库 (netinet/in.h)。


现在我明白我的 osockaddr 成员 sa_family 将与 AF_INET 相关,但我不清楚 sa_data 成员内部到底发生了什么......我是假设 port,addr,zerosockaddr_in 结构相关,但我不清楚。

问题: 谁能给我一个使用通用 osockaddr 结构的例子吗?

到目前为止我有什么....

#include<sys/socket.h>    
int main(void){
    struct osockaddr address;
    address.sa_family = AF_INET;
    address.sa_data = ? //What goes here (port, addr, zero)?
    return 0;
}

不要那样做。
您可以将 sockaddr 视为一种联合:

struct sockaddr
{
  short int sin_family;
  union {
    struct {
      unsigned short int   sin_port;
      struct in_addr       sin_addr;
      unsigned char        sin_zero[8];
    };
    unsigned char sa_data[14]
  };
};

所以是的,如果你取 sin_port 的两个字节,注意正确的字节顺序,你可以将它们放在 sa_data[0]sa_data[1] 中,然后你可以取 sin_addr的4个字节放在sa_data[2]sa_data[6].
但是你真的不应该这样做,因为它是一种非常糟糕的编程,它会让你的代码在 6 个月内无法被其他人阅读,包括你自己。
如果出于某种奇怪的原因你不想 #include "netinet/in.h" 你可以只在你自己的代码文件中定义这个结构并使用它。

netinet/in.h 不是 额外的库 ,它只是您要 link 针对任何库的定义的子集方式。

这个通用地址就像一个抽象基础-Class。你不应该创建它。只有当你不关心你有什么样的地址或者你想接受任何类型的地址时才使用它。

用法看起来像这样。

/* print any kind of socket address */
void prettyPrintAddress(struct sockaddr *addr) {
  switch (addr->sa_family) {
     case AF_INET:
       // Typocast to the actual type
       struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
       // print [ipv4]:protocl:ipv4:port
       break;
     case AF_INET6:
       // Typocast to the actual type
       struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)addr;
       // print [ipv6]:protocl:ipv6:port
       break;
     case AF_UNIX:
       // Typocast to the actual type
       struct sockaddr_un *un_addr = (struct sockaddr_un *)addr;
       // print [unix]:socket-path
       break;
     ...
  }
}

prettyPrintAddress(anyAddress);
prettyPrintAddress((struct sockaddr *) in_addr);
prettyPrintAddress((struct sockaddr *) in6_addr);
prettyPrintAddress((struct sockaddr *) un_addr);