【问题标题】:Connection refused when using abstract namespace unix sockets使用抽象命名空间 unix 套接字时连接被拒绝
【发布时间】:2015-11-01 17:36:54
【问题描述】:

在使用 Python 和“纯”C 时,使用所谓的抽象命名空间的 unix socket(美国)有一个奇怪的问题(Python 3.x,但看起来 2.x 也有同样的问题)。 “普通”插座就像一个魅力。使用“抽象”一美国,我的代码仅在我使用相同的“代码平台”(C 或 Python)时才有效。

首先我认为这与memset / str(n)cpy(参见Can not connect to an abstract unix socket in python)有关,但恕我直言,事实并非如此。

测试矩阵(srv - 服务器,cli - 客户端):

  • srv + cli @“抽象”unix 袜子:
    • python + python = OK
    • c + c = 确定
  • srv + cli @“正常”unix 袜子:
    • python + python = OK
    • c + c = 确定
  • srv + cli @“正常”unix 袜子:
    • python + c = OK
    • c + python = OK
  • srv + cli @“抽象”unix 袜子:
    • python + c = FAIL [cli / strace 输出:ECONNREFUSED(连接被拒绝)]
    • c + python = FAIL [cli / 引发异常:socket.error: [Errno 111] Connection denied]

/proc/net/unix / lsofstrace 显示没有异常:

  • 工作“正常”套接字 C 客户端:
    // ...
    socket(PF_LOCAL, SOCK_STREAM, 0) = 3
    connect(3, {sa_family=AF_LOCAL, sun_path=@"/var/tmp/sock.tmp"}, 110) = 0
    // ...

  • 行为不端的“抽象”套接字 C 客户端:
    // ...
    socket(PF_LOCAL, SOCK_STREAM, 0) = 3
    connect(3, {sa_family=AF_LOCAL, sun_path=@"/var/tmp/sock.tmp"}, 110) = -1 ECONNREFUSED (Connection refused)
    // ...

Python 错误还是什么...?

我的测试矩阵的代码示例要点:https://gist.github.com/soutys/ffbe2e76a86835a9cc6b

原始代码/示例:

2015 年 11 月 2 日更新

有关系统和编译的更多信息:

  • 主机系统:Ubuntu 14.04.3 LTS (x64);
  • 所有使用gcc编译的C测试文件(例如:gcc -Wall -Wextra -pedantic -o abs_cli abs_cli.c);
  • 所有程序(编译的和内置的 python)都以非 root 用户身份运行;

【问题讨论】:

  • 引用的'C'客户端代码,不能编译!!包括原始来源。除其他外,它缺少头文件:#include <string.h> 用于系统功能:memset()strncpy()。编译时始终启用所有警告,然后修复这些警告。 (对于 gcc,至少使用:-Wall -Wextra -pedantic
  • 另外,srv 和 cli 中的 C 代码确实遇到了链接帖子中描述的问题。 strncpy 只会复制 \0 空值,无论您将其作为 n (只要 n > 0)。使用 memcpy()。
  • @user3629249 它在我的 x64 ubuntu 上使用 gcc 编译,同时带有 -Wall-Wall -Wextra -pedantic... 好的 - 为了清楚起见,我添加了 string.h 标题条目。
  • @thuovila 您可能会看到 strncpy 发生了变化:strncpy(&addr.sun_path[1], socket_path, sizeof(addr.sun_path) - 2); 在零填充结构中给出了适当的“偏移量”。
  • 我可能看不到。我至少看过github.com/troydhanson/network/blob/master/unixdomain/srv.c 的版本中不存在它。此外,这不是一个非常明智的方法。如果您的数据中有空值,只需使用 memcpy()。

标签: python c sockets unix unix-socket


【解决方案1】:

在将 UNIX 域套接字绑定到抽象名称时,addrlen 参数应为 sizeof(struct sockaddr_un's sun_family) + 抽象名称中的字符数 + 1。“+1”用于抽象前面的空字节sockaddr_un 的 sun_path 中的名称。我们来看一个例子:

  • C 中的服务器:

    int sockfd;
    struct sockaddr_un addr;
    /* create socket, set addr.sun_family, set addr.sun_path to 
       null byte followed by abstract_name */
    bind(sockfd, (struct sockaddr *)&addr, sizeof(addr.sun_family) +
         strlen(abstract_name) + 1);
    
  • Python 中的客户端:

    client = socket.socket(socket.AF_UNIX, ...)
    client.connect( "\0abstract_name" )
    

参考资料:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-25
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    相关资源
    最近更新 更多