[英]Why do we cast sockaddr_in to sockaddr when calling bind()?
The bind() function accepts a pointer to a sockaddr
, but in all examples I've seen, a sockaddr_in
structure is used instead, and is cast to sockaddr
: bind()函数接受一个指向
sockaddr
的指针,但在我见过的所有示例中,都使用了sockaddr_in
结构,并将其sockaddr
为sockaddr
:
struct sockaddr_in name;
...
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
...
I can't wrap my head around why is a sockaddr_in
struct used.我无法
sockaddr_in
为什么使用sockaddr_in
结构。 Why not just prepare and pass a sockaddr
?为什么不准备并通过
sockaddr
?
Is it just convention?只是约定俗成吗?
No, it's not just convention.不,这不仅仅是约定俗成。
sockaddr
is a generic descriptor for any kind of socket operation, whereas sockaddr_in
is a struct specific to IP-based communication (IIRC, "in" stands for "InterNet"). sockaddr
是任何类型的套接字操作的通用描述符,而sockaddr_in
是特定于基于 IP 的通信的结构(IIRC,“in”代表“InterNet”)。 As far as I know, this is a kind of "polymorphism" : the bind()
function pretends to take a struct sockaddr *
, but in fact, it will assume that the appropriate type of structure is passed in;据我所知,这是一种“多态性”:
bind()
函数假装采用struct sockaddr *
,但实际上,它会假设传入了适当类型的结构; ie one that corresponds to the type of socket you give it as the first argument.即对应于您将其作为第一个参数提供的套接字类型。
I don't know if its very much relevant for this question, but I would like to provide some extra info which may make the typecaste more understandable as many people who haven't spent much time with C
get confused seeing such a typecaste.我不知道它是否与这个问题非常相关,但我想提供一些额外的信息,这可能会使类型等级更容易理解,因为许多没有花太多时间在
C
看到这样的类型等级会感到困惑。
I use macOS
, so I am taking examples based on header files from my system.我使用
macOS
,所以我根据系统中的头文件来举例。
struct sockaddr
is defined as follows: 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
is defined as follows: struct sockaddr_in
定义如下:
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];
};
Starting from the very basics, a pointer just contains an address.从最基本的开始,指针只包含一个地址。 So
struct sockaddr *
and struct sockaddr_in *
are pretty much the same.所以
struct sockaddr *
和struct sockaddr_in *
几乎相同。 They both just store an address.他们都只存储一个地址。 Only relevant difference is how compiler treats their objects.
唯一相关的区别是编译器如何处理它们的对象。
So when you say (struct sockaddr *) &name
, you are just tricking the compiler and telling it that this address points to a struct sockaddr
type.所以当你说
(struct sockaddr *) &name
,你只是在欺骗编译器并告诉它这个地址指向一个struct sockaddr
类型。
So let's say the pointer is pointing to a location 1000
.因此,假设指针指向位置
1000
。 If the struct sockaddr *
stores this address, it will consider memory from 1000
to sizeof(struct sockaddr)
possessing the members as per the structure definition.如果
struct sockaddr *
存储此地址,它将考虑从1000
到sizeof(struct sockaddr)
内存,这些内存拥有结构定义中的成员。 If struct sockaddr_in *
stores the same address it will consider memory from 1000
to sizeof(struct sockaddr_in)
.如果
struct sockaddr_in *
存储相同的地址,它将考虑从1000
到sizeof(struct sockaddr_in)
内存。
When you typecasted that pointer, it will consider the same sequence of bytes upto sizeof(struct sockaddr)
.当您对该指针进行类型转换时,它会考虑到
sizeof(struct sockaddr)
的相同字节序列。
struct sockaddr *a = &name; // consider &name = 1000
Now if I access a->sa_len
, the compiler would access from location 1000
to sizeof(__uint8_t)
which is same bytes size as in case of sockaddr_in
.现在,如果我访问
a->sa_len
,编译器将从位置1000
访问sizeof(__uint8_t)
,这与sockaddr_in
字节大小相同。 So this should access the same sequence of bytes.所以这应该访问相同的字节序列。
Same pattern is for sa_family
.相同的模式适用于
sa_family
。
After that there is a 14 byte character array in struct sockaddr
which stores data from in_port_t sin_port
( typedef
'd 16 bit unsigned integer = 2 bytes ) , struct in_addr sin_addr
(simply a 32 bit ipv4 address = 4 bytes) and char sin_zero[8]
(8 bytes).之后,
struct sockaddr
中有一个 14 字节的字符数组,它存储来自in_port_t sin_port
( typedef
'd 16 位无符号整数 = 2 字节)、 struct in_addr sin_addr
(简单的 32 位 ipv4 地址 = 4 字节)和char sin_zero[8]
(8 个字节)。 These 3 add up to make 14 bytes.这 3 个加起来就是 14 个字节。
Now these three are stored in this 14 bytes character array and we can access any of these three by accessing appropriate indices and typecasting them again.现在这三个存储在这个 14 字节的字符数组中,我们可以通过访问适当的索引并再次对它们进行类型转换来访问这三个中的任何一个。
user529758's answer already explains the reason to do this. user529758 的回答已经解释了这样做的原因。
This is because bind can bind other types of sockets than IP sockets, for instance Unix domain sockets, which have sockaddr_un as their type.这是因为 bind 可以绑定除 IP 套接字之外的其他类型的套接字,例如 Unix 域套接字,其类型为 sockaddr_un。 The address for an AF_INET socket has the host and port as their address, whereas an AF_UNIX socket has a filesystem path.
AF_INET 套接字的地址以主机和端口作为其地址,而 AF_UNIX 套接字具有文件系统路径。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.