SO_REUSEADDR和AF_UNIX

Hib*_*u57 21 unix sockets posix

事实

在POSIX文档中,我看不到阻止对UNIX域套接字使用SO_REUSEADDR套接字选项的任何内容AF_UNIX.

但是,bind如果套接字节点已经存在,它总是会失败,并且似乎被忽略,并且似乎需要在调用之前首先取消链接文件系统上的套接字节点bind; 简而言之,它不重用地址.关于这个问题,网上有很多线程,没有解决方案.

这个问题

我不会坚持,如果它不起作用,它不起作用(至少在BSD和Linux系统上似乎都是一样的),并且只是有一个问题:这是正常的行为吗?有没有提示应该支持的指针,或者相反,任何指示它不应该支持?或者这是未指定的?请注意,问题在POSIX上下文中提出,而不是在任何特定平台上下文中.

我欢迎任何POSIX参考此事.

额外:一个小小的片段,不要盲目unlink知道什么

我在网上看到了一些线程,建议unlink任何节点之前的预期名称bind.我觉得它不安全,在这种情况下,应该只取消链接已经是套接字节点的节点:ex.取消链接名为的文本文件以mysocket重新创建同名的套接字节点可能是错误的.在这个目的中,这是一个小小的片段:

/* Create the socket node
 * ----------------------
 * Note `SO_REUSEADDR` does not work with `AF_UNIX` sockets,
 * so we will have to unlink the socket node if it already exists,
 * before we bind. For safety, we won't unlink an already existing node
 * which is not a socket node. 
 */

status = stat (path, &st);
if (status == 0) {
   /* A file already exists. Check if this file is a socket node.
    *   * If yes: unlink it.
    *   * If no: treat it as an error condition.
    */
   if ((st.st_mode & S_IFMT) == S_IFSOCK) {
      status = unlink (path);
      if (status != 0) {
         perror ("Error unlinking the socket node");
         exit (1);
      }
   }
   else {
      /* We won't unlink to create a socket in place of who-know-what.
       * Note: don't use `perror` here, as `status == 0` (this is an
       * error we've defined, not an error returned by a system-call).
       */
      fprintf (stderr, "The path already exists and is not a socket node.\n");
      exit (1);
   }
}
else {
   if (errno == ENOENT) {
      /* No file of the same path: do nothing. */
   }
   else {
      perror ("Error stating the socket node path");
      exit (1);
   }
}

/* … invoke `bind` here, which will create the socket node … */
Run Code Online (Sandbox Code Playgroud)

Mar*_*ins 32

我只能访问一个POSIX规范文档,即系统接口,所以我将从这里做到最好.

我们的规范探险冒险当然必须从2.10.6 选项的使用开始,该选项定义SO_REUSEADDR如下选项:

SO_REUSEADDR选项指示用于验证bind()中提供的地址的规则应允许重用本地地址.此选项的操作是特定于协议的.SO_REUSEADDR的默认值为off; 也就是说,不允许重用本地地址.

通过将该选项委托给底层协议的规范,本段基本上不对该选项真正做什么做出任何规范.

2.10.17节针对本地UNIX连接的使用描述了创建UNIX域套接字的机制,但它实际上唯一告诉我们的是要使用的套接字类型常量以及用于地址的结构.结构的文档sockattr_un只告诉我们它的格式,而不是它的行为bind.

bind本身的文档可以理解为与协议无关,只告诉我们当地址已被使用时会发生什么,而不是重新绑定同一套接字有效的情况.

虽然它不是POSIX标准文档,但富士通有一个关于POSIX套接字API的文档,如果仅仅因为它不是专门针对Linux或BSD,那么这个文档很有意思.bind有关UNIX套接字的行为,请参阅本文档的2.6.4部分:

必须在sun.sun_path组件中指定的路径名​​称将在文件系统中使用创建为文件bind().bind()因此,调用的进程必须具有对要写入文件的目录的写权限.系统不会删除该文件.因此,当不再需要时,应该删除该过程.

虽然这说,大约没什么SO_REUSEADDR特别,但它确实状态的行为bind创建一个文件,它是结合过程的责任不再受到使用时将其删除.

最后,本文档的描述setsockopt有如下说法SO_REUSEADDR:

指定对bind()指定的地址进行有效性检查的规​​则应允许重用本地地址,前提是协议支持此地址.

因此,虽然没有具体提及AF_UNIX,但它确实承认此选项不适用于所有协议.

我还发现描述一个(非授权)总结预期的目的SO_REUSEADDR:

这个套接字选项告诉内核即使这个端口忙(处于TIME_WAIT状态),也要继续并重新使用它.如果它很忙,但是有另一个状态,你仍然会得到一个已经处于使用中的地址错误.

TIME_WAIT状态主要用于面向Internet的套接字,以避免新程序绑定到最近被另一个程序使用的端口,并且无意中接收到与旧程序相关的数据包.这个问题可以说并不适用于UNIX域套接字,因为它很可能两个方案将试图创建的相同路径的插座,因此,如果TIME_WAIT没有为Unix套接字实现,那么这可能是为什么一个解释(的近似值)SO_REUSEADDR做不适用于AF_UNIX.