Linux 为什么我们在调用 bind() 时将 sockaddr_in 转换为 sockaddr?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21099041/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 01:50:42  来源:igfitidea点击:

Why do we cast sockaddr_in to sockaddr when calling bind()?

clinuxsockets

提问by sashoalm

The bind()function accepts a pointer to a sockaddr, but in all examples I've seen, a sockaddr_instructure is used instead, and is cast to sockaddr:

绑定()函数接受一个指针sockaddr,但在我看到所有的实施例中,sockaddr_in结构来代替,并且被转换为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_instruct used. Why not just prepare and pass a sockaddr?

我无法理解为什么使用sockaddr_in结构体。为什么不准备并通过一个sockaddr

Is it just convention?

只是约定俗成吗?

采纳答案by sashoalm

No, it's not just convention.

不,这不仅仅是约定俗成。

sockaddris a generic descriptor for any kind of socket operation, whereas sockaddr_inis a struct specific to IP-based communication (IIRC, "in" stands for "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; i. e. one that corresponds to the type of socket you give it as the first argument.

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

回答by Magnus Reftel

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. The address for an AF_INET socket has the host and port as their address, whereas an AF_UNIX socket has a filesystem path.

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

回答by Mihir

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 Cget confused seeing such a typecaste.

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

I use macOS, so I am taking examples based on header files from my system.

我使用macOS,所以我根据系统中的头文件来举例。

struct sockaddris 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_inis 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. They both just store an address. Only relevant difference is how compiler treats their objects.

从最基本的开始,指针只包含一个地址。所以struct sockaddr *struct sockaddr_in *几乎相同。他们都只存储一个地址。唯一相关的区别是编译器如何处理它们的对象。

So when you say (struct sockaddr *) &name, you are just tricking the compiler and telling it that this address points to a struct sockaddrtype.

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



So let's say the pointer is pointing to a location 1000. If the struct sockaddr *stores this address, it will consider memory from 1000to sizeof(struct sockaddr)possessing the members as per the structure definition. If struct sockaddr_in *stores the same address it will consider memory from 1000to sizeof(struct sockaddr_in).

所以假设指针指向一个 location 1000。如果struct sockaddr *存储此地址,它将根据结构定义考虑从内存1000sizeof(struct sockaddr)拥有成员。如果struct sockaddr_in *存储相同的地址,它将考虑从1000to 的内存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 1000to sizeof(__uint8_t)which is same bytes size as in case of sockaddr_in. So this should access the same sequence of bytes.

现在,如果我的访问a->sa_len,编译器会从一个地方访问1000sizeof(__uint8_t)它是相同的字节大小的情况下sockaddr_in。所以这应该访问相同的字节序列。

Same pattern is for sa_family.

相同的模式适用于sa_family.

After that there is a 14 byte character array in struct sockaddrwhich 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). These 3 add up to make 14 bytes.

之后有一个 14 字节的字符数组,struct sockaddr其中存储来自in_port_t sin_port( typedef'd 16 位无符号整数 = 2 字节)、struct in_addr sin_addr(简单的 32 位 ipv4 地址 = 4 字节) 和char sin_zero[8](8 字节) 的数据。这 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 的回答已经解释了这样做的原因。