【问题标题】:Socket Programming (sys/socket.h)套接字编程 (sys/socket.h)
【发布时间】:2015-12-21 00:02:00
【问题描述】:

查看它列出的定义 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,zero 与@987654334 相关@结构,但我不清楚。

问题:谁能给我一个使用通用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;
}

【问题讨论】:

    标签: c sockets websocket ip webserver


    【解决方案1】:

    netinet/in.h 不是额外的库,它只是您要以任何方式链接的一个库的定义子集。

    这个通用地址就像一个抽象基类。你不应该创建它。仅当您不关心自己拥有什么样的地址或想要接受任何类型的地址时才使用它。

    用法如下所示。

    /* 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);
    

    【讨论】:

    • 我将初始化并链接整个 netinet/in.h 文件,所以它是额外的......而且我不需要链接它,sys/socket.h 定义了 socket(),bind( ),listen(),rec(),send() 没有它就可以完全正常工作...
    • 不,没有任何东西与头文件相关联。这不是 Java 或您来自的任何语言。两个头文件属于同一个标准库。 netinite/in.h 只是告诉你这个库的一些特性。不包括它并不意味着不包括这些功能。你甚至可以在不包括它的情况下使用这些功能。
    • 一切都已链接......如果我不#include&lt;netinet/in.h&gt; 头文件,我将无法使用该文件“功能”中定义的任何内容...... #include 是编译器的预处理器指令...如果我不#include该文件,我将不会初始化其中的任何内容,从而使我的程序更高效...
    • 没有。处理器与链接无关。我的观察是你对头文件的理解完全错误。
    • 预处理器!!! gcc.gnu.org/onlinedocs/cpp/…
    【解决方案2】:

    不要那样做。
    您可以将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",你可以在你自己的代码文件中定义这个结构并使用它。

    【讨论】:

    • 为什么使用标准的sys/socket.h libs 结构这么“奇怪”? lib不是为这个确切目的而设计的吗?如果编程如此糟糕,为什么它是标准(并获得 ISO 批准)?如果该库用于套接字 sys/socket.h 并定义了它自己的结构......为什么使用它会是糟糕的编程?对我来说,包括并初始化另一个库来修补听起来像糟糕的编程......
    • socket.h 旨在支持任何类型的套接字。您需要一个 IP 套接字,因此您需要使用 netinet/in.h(套接字库的一个组成部分)中的 IP 套接字的标准结构。 socket.h 不包括所有类型的套接字的所有结构,因为它们有很多,您也可以定义自己的。 sockaddr 并不是要自己实例化,它只是一个占位符,它是 C++ 抽象基类的 C 等价物。
    • 是的,通用套接字结构osockaddr 可以支持任何类型的结构,所以我只是在寻找与AF_INET 家族一起使用...您的答案几乎在上面为我定义了,使用两个字节作为端口,sa_data 中的 4 个字节 addr 知道我有一个 IPv4 地址并且知道我要将它绑定到哪个端口,我可以相应地更改 sa_data[14] 长度。是的,我知道这不是“便携式”解决方案,因为可能有一个 IPv6 地址会改变长度……但我知道它是一个 IPv4。
    • 我知道netinet/in.h 是套接字库的“不可或缺”部分,我同意你的观点,但它不是套接字库的“必需”部分,所以我的问题基本上是如何看起来会不会...在 sa_data[] 中定义 IPv4 地址和端口,而不添加 netinet/in.h 结构...
    • IPv6 会有不同的sin_family。我的推理严格地属于“不要让其他需要阅读你的代码的人想用棒球棒打你”,如果我看到这样的代码,这就是我想做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2020-07-25
    • 2015-12-12
    • 2021-08-15
    • 2011-02-26
    • 1970-01-01
    相关资源
    最近更新 更多