为什么在套接字编程中需要 Value-Result 参数? (需要澄清)

Why do we need Value-Result arguments in socket programming? (Clarification required)

当被问到"What is a Value-Result argument and WHY is it needed in Socket Programming?"

这样的问题时,我有点困惑

尽管阅读了无数页面和此处的其他问题,但我仍在努力完全理解值结果参数到底是什么。

我的理解是,在值结果参数中,内核能够更改传递的参数(因为我们给它一个 reference/pointer,而不仅仅是它的值)和 return 它到调用它的 process/function。它既是调用函数时的 "value"(告诉内核结构的大小,例如它不会写太多),又是函数 returns 时的结果(我们实际写了多少在结构中)。

我很难回答的是,为什么这在套接字编程中如此重要?特别是,当我们处理 sockaddr 结构并将它们的引用和大小传递过来时,即 accept()

我知道这个问题听起来有点傻,但如果能对此做出任何澄清就更好了,在此先感谢您。

您对什么是值-结果参数的理解是正确的。您将输入值分配给变量并通过引用传递它,以便函数可以使用输出值修改变量。这样就不必为输出传递单独的参数,或更改函数的 return 值的语义。

原因需要sockaddr参数是因为不同的传输实现不同的sockaddr_...结构,这些结构具有不同的大小和布局(sockaddr_in 用于 IPv4,sockaddr_in6 用于 IPv6,sockaddr_un 用于 UNIX 域套接字等)。大多数平台还提供 sockaddr_storage 结构的实现,它足够容纳所有其他 sockaddr_... 结构,在编写多传输代码时很有用。

因此,在 accept() 的情况下,您必须传入将接收客户端 sockaddr_... 的缓冲区的完整大小。当新客户端到达时,accept() 将在填充缓冲区之前验证缓冲区是否足够大以接收客户端的实际 sockaddr_... 数据,并且 return 缓冲区实际有多少填写.

例如,如果您知道套接字仅支持 IPv4(创建为 AF_INET 系列套接字),则可以使用 sockaddr_in 作为缓冲区并使用 sizeof(sockaddr_in)作为缓冲区大小,或者您可以使用 sockaddr_storage 作为缓冲区和 sizeof(sockaddr_storage) 作为缓冲区大小。在任何一种情况下,accept() 都会用 sockaddr_in 填充缓冲区,return 缓冲区大小为 sizeof(sockaddr_in)。与仅 IPv6 套接字相同(创建为 AF_INET6 系列套接字),只是用 sockaddr_in6 代替。

现在,假设您有一个同时支持 IPv4 和 IPv6 的双栈套接字(AF_INET6 系列套接字,禁用了 IPV6_V6ONLY 选项)。您可以使用 sockaddr_storage 作为缓冲区并使用 sizeof(sockaddr_storage) 作为缓冲区大小,并且 accept() 将使用 sockaddr_insockaddr_in6 和 return 适当的缓冲区大小,具体取决于是否接受了 IPv4 或 IPv6 客户端。然后,您可以读取 sockaddr_storagess_family 字段并将数据类型转换为 sockaddr_in for AF_INETsockaddr_in6 for AF_INET6