如何使用 recvfrom 获取 AF_INET6 套接字的地址

Posted

技术标签:

【中文标题】如何使用 recvfrom 获取 AF_INET6 套接字的地址【英文标题】:How to get an addres of AF_INET6 socket with recvfrom 【发布时间】:2013-08-20 21:34:23 【问题描述】:

recvfrom 要求第 5 个参数是指向 sockaddr 结构的指针,第 6 个参数是指向 socklen_t 的指针。

man recvfrom (3) 说:

如果地址的实际长度大于 提供的 sockaddr 结构,存储的地址将被截断。

我不明白如何使用 AF_INET6 地址族检索发送套接字的地址,因为sockaddr_in6 的大小大于sockaddr,因此它将被recvfrom 截断。

recvfrom 无法检索大于sizeof(sockaddr) 的地址,我理解了吗?

即使我定义sockaddr_in6 的实例将其地址转换为sockaddr* 并将其传递给recvfrom,我是否理解正确,该函数将无法知道有足够的空间来存储地址?

【问题讨论】:

【参考方案1】:

将其转换为sockaddr* 是正确的。

此外,人们经常使用sockaddr_storage,因为它是defined

标题应定义 sockaddr_storage 结构。 该结构应为:

足够大,可以容纳所有受支持的特定于协议的地址结构 在适当的边界对齐,以便指向它的指针可以转换为指向协议特定地址结构的指针并用于 在没有对齐问题的情况下访问这些结构的字段

通过这种方式,您可以将它用于多种协议,因此您不仅限于 IPv6 或 IPv4。

所以你可以这样做

struct sockaddr_storage addr;
socklen_t sa_len = sizeof(addr);

recvfrom (sock, buffer, sizeof (buffer), (struct sockaddr*) &addr, &sa_len);

如果您需要知道 sockaddr 的 kinf 是什么,您可以检查每个 sockaddr 结构中存在的强制性 sa_family_t ss_family 字段。

您可能还对此link 或one 感兴趣。

【讨论】:

感谢您提供sockaddr_storage 参考,这真的很有帮助 您对使用sockaddr_storage有负面经验或参考吗?我问是因为你提到了它,从那以后我一直像魔鬼一样避免它,唯一的原因是在某些平台上它是一个巨大的结构。 sockaddr_in6 到目前为止一直为我工作,但“一直为我工作”的真正含义是什么...... 好吧,据我所知,这是处理多协议案例的好习惯。该标准没有规定所有 sockaddr 结构的大小(不禁止对齐优化,即使它与在线上运行的不同),唯一的规定是 sockadrr_storage 必须足够大以容纳任何其中。【参考方案2】:

您将sockaddr_in6(类型转换)的指针和sockaddr_in6 结构的大小作为参数传递:

struct sockaddr_in6 in6;
socklen_t len6 = sizeof(in6);

recvfrom(sock, buf, buflen, (struct sockaddr *) &in6, &len6);

由于您将正确的长度传递给函数,因此它将起作用。

【讨论】:

感谢您的回答。我曾经认为最后一个参数是提供给recvfrom,以便函数用实际的发件人地址填充它。我误会了吗?或者最后一个参数有两个目的:在调用recvfrom 之前指示可用的地址缓冲区大小和调用之后存储实际地址大小? @Kolyunya 它用于两者。当你调用函数时,你告诉它套接字地址结构有多大,当它返回时,函数将它设置为它用来填充结构的大小。

以上是关于如何使用 recvfrom 获取 AF_INET6 套接字的地址的主要内容,如果未能解决你的问题,请参考以下文章

socket-简单实现

UDP协议编程与获取一个网页内容

UDP协议编程与获取一个网页内容

套接字编程阻塞程序

udp的recvfrom函数,能接收指定ip和端口发送来的数据吗?

modbustcp封装使用获取设备数据示例