套接字选项是否从侦听套接字继承到accept()?

时间:2011-05-11 17:23:18

标签: c sockets posix

假设传递给accept的侦听套接字使用setsockopt设置了非默认选项。这些选项(部分或全部?)是由接收连接的结果文件描述符继承的吗?

5 个答案:

答案 0 :(得分:9)

在系统的较低级别处理了几个套接字选项。虽然可以使用setsockopt设置大多数套接字选项。参考:man setsockopt因为你在任何Linux上都只提到POSIX,一般来说,作为你的范围。 accept()(参考:man accept)对于应继承哪些套接字选项以及从侦听fd拒绝哪些选项有一定的自由裁量权。

accept()不会修改作为参数传递给它的原始套接字。 accept()返回的新套接字不会从侦听套接字继承文件状态标志,如O_NONBLOCK,O_ASYNC。

因此,不是依赖于侦听套接字属性的继承或非继承(它必须在实现和许可证之间变化),应该使用所需的套接字选项显式设置接受的套接字。(最佳实践)< / p>

手册页和机器中的实现代码将是accept()行为最相关的规范。在Linux的多个变体中没有共同或标准规范。

答案 1 :(得分:4)

不,他们不一定是继承的。试试这个示例,它将初始套接字上的接收缓冲区大小(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-generic的计算机上的结果:

initial rcvbuf: 87380
set rcvbuf to 174760
accepted connection
new rcvbuf: 262142

答案 2 :(得分:3)

套接字选项是一些不适合其他地方的东西。因此,期望不同的套接字选项具有不同的继承行为。是否继承套接字选项取决于具体情况。

答案 3 :(得分:1)

如果他们不是,那将是惊人的。

但是,一旦套接字接受了连接,它们中的一些可能变得无关紧要(例如,未完成的连接请求的数量)。

答案 4 :(得分:1)

在我阅读本文时,对于符合POSIX的实现,答案是否定的。

根据POSIX-2017规范中的accept():

accept()函数应提取未决连接队列中的第一个连接,创建一个具有与指定套接字相同的套接字类型协议和地址族的新套接字,并为该套接字分配一个新的文件描述符。 >

请注意,它显然是“新套接字”,而不是“正在排队的套接字的完整或部分副本”,因此,该套接字类型和地址系列的默认选项应与默认值相同。尽管复制行为可能是理想的,但这留作平台可能具有的扩展接口。但是,我还没有看到任何平台可以实现该平台,因此可以将其添加到标准中。因此,在应用程序上,使用getsockopt()/ setsockopt()将任何与默认值不同的属性从队列套接字复制到返回的套接字,而不是接口的责任,然后再使用该套接字发送或接收数据。