当被问及诸如“什么是值-结果参数以及为什么在套接字编程中需要它?”之类的问题时,我有点困惑。
尽管阅读了无数页面和此处的其他问题,但我仍在努力完全理解值(value)结果论证到底是什么。
我的理解是,在值结果参数中,内核能够更改传递的参数(因为我们给它一个引用/指针,而不仅仅是它的值)并将它返回给调用的进程/函数它。它既是调用函数时的“值”(例如告诉内核结构的大小,因此它不会写太多),又是函数返回时的结果(我们实际在结构中写了多少)。
我很难回答的是,为什么这在套接字编程中如此重要?特别是,当我们处理 sockaddr
结构并将它们的引用和大小传递过来时,即 accept()
我意识到这个问题可能听起来有些愚蠢,但如果对此有任何澄清就更好了,在此先感谢您。
最佳答案
您对值-结果参数什么有正确的理解。您将输入值分配给变量并通过引用传递它,以便函数可以使用输出值修改变量。这样就不必为输出传递单独的参数,也不必更改函数返回值的语义。
sockaddr
参数需要这个的原因是因为不同的传输实现不同的sockaddr_...
结构,这些结构具有不同的大小和布局(sockaddr_in
用于 IPv4,sockaddr_in6
用于 IPv6,sockaddr_un
用于 UNIX 域套接字等)。大多数平台还提供了 sockaddr_storage
结构的实现,它足够大以容纳所有其他 sockaddr_...
结构,并且在编写多传输代码时很有用。
因此,在 accept()
的情况下,您必须传入将接收客户端的 sockaddr_...
的缓冲区的完整大小。当新客户端到达时,accept()
将在填充缓冲区之前验证缓冲区是否足够大以接收客户端的实际 sockaddr_...
数据,然后返回实际填充了多少缓冲区。
例如,如果您知道套接字仅支持 IPv4(创建为 AF_INET
系列套接字),那么您可以使用 sockaddr_in
作为缓冲区并且 sizeof(sockaddr_in)
作为缓冲区大小,或者您可以使用 sockaddr_storage
作为缓冲区,使用 sizeof(sockaddr_storage)
作为缓冲区大小。在任何一种情况下,accept()
都会用 sockaddr_in
填充缓冲区并将缓冲区大小返回为 sizeof(sockaddr_in)
。与仅 IPv6 套接字(创建为 AF_INET6
系列套接字)相同,只是使用 sockaddr_in6
代替。
现在,假设您有一个同时支持 IPv4 和 IPv6 的双栈套接字(一个 AF_INET6
系列套接字,禁用了 IPV6_V6ONLY
选项)。您可以使用 sockaddr_storage
作为缓冲区,使用 sizeof(sockaddr_storage)
作为缓冲区大小,accept()
将使用sockaddr_in
或 sockaddr_in6
并返回适当的缓冲区大小,具体取决于是否接受了 IPv4 或 IPv6 客户端。然后,您可以读取 sockaddr_storage
的 ss_family
字段并将数据类型转换为 sockaddr_in
for AF_INET
或sockaddr_in6
用于 AF_INET6
。
关于c++ - 为什么在套接字编程中需要 Value-Result 参数? (需要澄清),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30639056/