假设传递给accept
的监听套接字在setsockopt
上设置了非默认选项。这些选项(部分还是全部?)是否被接受的连接的结果文件描述符继承?
几个套接字选项在系统的较低级别处理。虽然大多数套接字选项都可以使用setsockopt进行设置。参考:man setsockopt
并且由于您通常只在任何Linux上提及POSIX作为范围。 accept()
(参考:man accept
)对于应继承哪些套接字选项以及从侦听fd拒绝哪些选项确实有一定的酌处权。
accept()不会修改作为参数传递给它的原始套接字。由accept()返回的新套接字不会从侦听套接字继承文件状态标志,例如O_NONBLOCK,O_ASYNC。
因此,不要依赖于侦听套接字属性的继承或非继承(绑定在实现和许可证上会有所不同),应该使用所需的套接字选项显式设置接受的套接字。(最佳实践)
您机器中的手册页和实现代码将是与accept()行为最相关的规范。在Linux的多个变体中不存在通用或标准规范。
不,它们不一定是继承的。尝试使用此示例,该示例将初始套接字上的接收缓冲区大小(SO_RCVBUF
)设置为非默认值,然后将结果与继承的套接字进行比较。运行此代码,该代码侦听TCP端口12345,然后从任何其他程序连接到它。
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
void die(const char *f)
{
printf("%s: %s\n", f, strerror(errno));
exit(1);
}
int main(void)
{
int s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
die("socket");
int rcvbuf;
socklen_t optlen = sizeof(rcvbuf);
if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (1)");
printf("initial rcvbuf: %d\n", rcvbuf);
rcvbuf *= 2;
if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
die("setsockopt");
printf("set rcvbuf to %d\n", rcvbuf);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(12345);
sin.sin_addr.s_addr = INADDR_ANY;
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
die("bind");
if(listen(s, 10) < 0)
die("listen");
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int s2 = accept(s, (struct sockaddr *)&client_addr, &addr_len);
if(s2 < 0)
die("accept");
printf("accepted connection\n");
optlen = sizeof(rcvbuf);
if(getsockopt(s2, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (2)");
printf("new rcvbuf: %d\n", rcvbuf);
return 0;
}
在运行Linux 3.0.0-21-通用的计算机上的结果:
initial rcvbuf: 87380
set rcvbuf to 174760
accepted connection
new rcvbuf: 262142
套接字选项是其他地方无法使用的地方。因此,期望不同的套接字选项具有不同的继承行为。是否继承套接字选项取决于具体情况。
如果没有,那将是惊人的。
尽管其中的一些可能在套接字接受连接后变得无关紧要(例如,未完成的连接请求数)。
对于我所读的符合POSIX的实现,答案是否定的。
从POSIX-2017规范的accept():
accept()函数应提取未决连接队列中的第一个连接,创建一个与指定套接字具有相同套接字类型协议和地址族的新套接字,并为该套接字分配一个新的文件描述符。
请注意,它显然是“新套接字”,而不是“要取消排队的套接字副本”,因此,该套接字类型和地址系列的默认选项应与默认值相同。尽管复制行为可能是理想的,但这留作平台可能具有的扩展接口。我还没有看到任何平台能够实现这一点,因此可以将其添加到标准中。因此,在应用程序上,使用getsockopt()/ setsockopt()将与默认值不同的所有属性从队列套接字复制到返回的套接字,而不是接口在使用该套接字发送或发送消息之前的职责。接收数据。