Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
调用bind()时,为什么要将sockaddr_强制转换为sockaddr?_C_Linux_Sockets - Fatal编程技术网

调用bind()时,为什么要将sockaddr_强制转换为sockaddr?

调用bind()时,为什么要将sockaddr_强制转换为sockaddr?,c,linux,sockets,C,Linux,Sockets,该函数接受指向sockaddr的指针,但在我看到的所有示例中,都使用了结构中的sockaddr\u,并强制转换为sockaddr: struct sockaddr_in name; ... if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) ... struct sockaddr\u的名称; ... if(bind(sock,(struct sockaddr*)&name,sizeof(name)) 100

该函数接受指向
sockaddr
的指针,但在我看到的所有示例中,都使用了
结构中的
sockaddr\u,并强制转换为
sockaddr

struct sockaddr_in name;
...
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
...
struct sockaddr\u的名称;
...
if(bind(sock,(struct sockaddr*)&name,sizeof(name))<0)
...
我不明白为什么要在
结构中使用
sockaddr\u。为什么不准备并传递一个
sockaddr


这只是惯例吗?

不,这不仅仅是惯例


sockaddr
是任何类型套接字操作的通用描述符,而
sockaddr\u in
是特定于基于IP的通信(IIRC,“in”代表“InterNet”)的结构。据我所知,这是一种“多态性”:函数
bind()
假装接受一个
struct sockaddr*
,但实际上,它会假定传入了适当类型的结构;我E与作为第一个参数提供的套接字类型相对应的套接字。

这是因为bind可以绑定IP套接字以外的其他类型的套接字,例如Unix域套接字,其类型为sockaddr\u un。AF_INET套接字的地址以主机和端口作为其地址,而AF_UNIX套接字有一个文件系统路径。

我不知道它是否与这个问题非常相关,但是我想提供一些额外的信息,这可能会使类型分类更容易理解,因为许多没有花太多时间在
C
上的人看到这样的类型分类会感到困惑

我使用的是
macOS
,因此我以系统中的头文件为基础进行示例

struct sockaddr
定义如下:

struct sockaddr {
    __uint8_t       sa_len;         /* total length */
    sa_family_t     sa_family;      /* [XSI] address family */
    char            sa_data[14];    /* [XSI] addr value (actually larger) */
};
struct sockaddr_in {
    __uint8_t       sin_len;
    sa_family_t     sin_family;
    in_port_t       sin_port;
    struct  in_addr sin_addr;
    char            sin_zero[8];
};
中的结构sockaddr\u定义如下:

struct sockaddr {
    __uint8_t       sa_len;         /* total length */
    sa_family_t     sa_family;      /* [XSI] address family */
    char            sa_data[14];    /* [XSI] addr value (actually larger) */
};
struct sockaddr_in {
    __uint8_t       sin_len;
    sa_family_t     sin_family;
    in_port_t       sin_port;
    struct  in_addr sin_addr;
    char            sin_zero[8];
};
从最基本的开始,指针只包含一个地址。因此*
中的
struct sockaddr*
struct sockaddr\u几乎是一样的。它们都只存储一个地址。唯一相关的区别是编译器如何处理它们的对象

因此,当你说
(struct sockaddr*)&name
,你只是在欺骗编译器,告诉它这个地址指向一个
struct sockaddr
类型


假设指针指向一个位置
1000
。如果<代码>结构SOCKADDR*<代码>存储此地址,它将考虑从代码< > 1000代码>代码> >代码> SIEZOF(StultSoCKADDR)按照结构定义拥有成员。如果<代码>结构SOCKADDRIGIN *<代码>存储相同的地址,它将考虑内存从<代码> 1000代码>到<代码> siZeof(StutoSokAdDrILIN)


当您键入该指针时,它会考虑到相同的字节序列(<>代码> siZeof(StultSoCKADDR)

现在,如果我访问
a->sau len
,编译器将从位置
1000
访问
sizeof(\uu uint8\u t)
,这与
中的sockaddr\u的字节大小相同。所以这应该访问相同的字节序列

同样的模式适用于
sa_系列

在这之后,
struct sockaddr
中有一个14字节的字符数组,它将
中的数据存储在\u-port\t sin\u-port
typedef
'd 16位无符号整数=2字节)、
struct in\u-addr sin\u-addr
(仅32位ipv4地址=4字节)和
char sin-zero[8]
(8字节)。这3个加起来就是14个字节

现在这三个都存储在这个14字节字符数组中,我们可以通过访问适当的索引并再次键入来访问这三个中的任何一个


user529758的回答已经解释了这样做的原因。

NB
sockaddr\u in 6
也存在,任何编写新代码的人都应该明智地将其包括在内……您在代码中省略了一个非常重要的部分:
name.sa\u family=AF\u INET
for
struct sockaddr\u in
!考虑<代码>结构SOCKADDR 是所有其他SoCKADDR类型的结合。唯一的共同点是,它们有一个第一个成员
sau family\t sau family
,必须与实际的结构类型相对应。只需添加:
sockaddr\u in6
用于IPv6地址,
sockaddr\u un
用于Unix域套接字,@MartinR I也在考虑蓝牙(如果我没有弄错的话,Linux是通过套接字进行RFCOMM的)等等。有很多套接字类型我都不知道……值得一提的是
struct sockaddr_storage
,它在某种意义上也是“通用的”,并且足够大,可以容纳任何类型的套接字地址。