26

事实

在 POSIX 文档中,我看不到任何阻止将SO_REUSEADDR套接字选项与AF_UNIXUNIX 域套接字一起使用的东西。

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

问题

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

我欢迎关于此事的任何 POSIX 参考。

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

我在网上看到了一些线程,建议unlinkbind. 我觉得这是不安全的,在这种情况下应该只取消链接已经是套接字节点的节点:例如。取消链接名为的文本文件以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 … */
4

1 回答 1

35

我只能访问一个 POSIX 规范文档,即System Interfaces,所以我将从这里尽力而为。

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

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

通过将其委托给底层协议的规范,本段基本上否认了该选项真正做什么的任何规范。

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

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

尽管它不是 POSIX 标准文档,但富士通有一个关于 POSIX 套接字 API 的文档,这很有趣,因为它不是专门针对 Linux 或 BSD 的。bind本文档的第 2.6.4 节对 UNIX 套接字的行为有以下说明:

必须在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.

于 2013-03-30T09:55:50.447 回答