7

我正在使用 unix 本地套接字(AF_UNIX 地址系列,即不是 UDP)上的数据报实现一个简单的服务。服务器绑定到一个公共地址,它接收请求就好了。不幸的是,在回复时,sendto除非客户端也被绑定,否则会失败。(常见的错误是Transport endpoint is not connected)。

绑定到一些随机名称(基于文件系统或抽象)有效。但我想避免这种情况:我是谁来保证我选择的名字不会发生冲突?

unix 套接字的流模式文档告诉我们,connect如果它们还没有抽象名称,那么它们将在时间分配给它们。这样的功能可用于面向数据报的套接字吗?

4

4 回答 4

6

我引用的unix(7)手册页包含有关自动绑定 UNIX 套接字的以下信息:

如果 bind(2) 调用将 addrlen 指定为 sizeof(sa_family_t),或者为未显式绑定到地址的套接字指定了 SO_PASSCRED 套接字选项,则套接字将自动绑定到抽象地址。

这就是 Linux 内核检查地址长度是否等于 sizeof(short) 的原因,因为 sa_family_t 是一个short。Rob 的出色答案引用的另一个 unix(7) 手册页说客户端套接字总是在连接时自动绑定,但是因为 SOCK_DGRAM 套接字是无连接的(尽管在它们上调用了连接),我相信这仅适用于 SOCK_STREAM 套接字。

另请注意,当提供您自己的抽象命名空间套接字名称时,此命名空间中的套接字地址由 sun_path 中的附加字节给出,这些字节由地址结构的指定长度覆盖。

struct sockaddr_un me;
const char name[] = "\0myabstractsocket";
me.sun_family = AF_UNIX;
// size-1 because abstract socket names are not null terminated
memcpy(me.sun_path, name, sizeof(name) - 1);
int result = bind(fd, (void*)&me, sizeof(me.sun_family) + sizeof(name) - 1);

sendto() 同样应该限制地址长度,而不是通过 sizeof(sockaddr_un)。

于 2011-12-15T16:58:38.433 回答
4

我假设您正在运行 Linux;我不知道这个建议是否适用于 SunOS 或任何 UNIX。

首先,答案:在socket()之后和connect()或者第一个sendto()之前,尝试添加这段代码:

struct sockaddr_un me;
me.sun_family = AF_UNIX;
int result = bind(fd, (void*)&me, sizeof(short));

现在,解释:unix(7)手册页是这样说的:

当套接字连接并且它还没有本地地址时,将自动生成抽象命名空间中的唯一地址。

可悲的是,手册页是谎言。

检查Linux 源代码,我们看到 unix_dgram_connect() 只有在套接字标志中设置了 SOCK_PASSCRED 时才调用 unix_autobind()。由于我不知道 SOCK_PASSCRED 是什么,现在是凌晨 1:00,我需要寻找另一种解决方案。

检查unix_bind,我注意到如果传入的大小等于“sizeof(short)”,则 unix_bind 调用 unix_autobind。因此,上面的解决方案。

祝你好运,早上好。

于 2008-09-20T06:15:00.623 回答
1

有点迟到了,但是对于像我一样使用谷歌找到这个的人。Rob Adam 的回答帮助我得到了“真正”的答案:只需使用 set (level SO_SOCKET, see man 7 unix) 设置SO_PASSCRED为 1。不需要愚蠢的绑定。

我在 PHP 中使用了它,但它没有SO_PASSCRED定义(愚蠢的 PHP)。但是,如果您自己定义它,它仍然有效。在我的电脑上,它的值是 16,我认为它可以很方便地工作。

于 2009-08-16T12:35:03.267 回答
-1

我不太确定我是否完全理解您的问题,但这是我刚刚编写的回显服务器的数据报实现。您可以看到服务器在发送它的同一 IP/PORT 上响应客户端。

这是代码

一、服务器(监听器)

from socket import *
import time
class Listener:
    def __init__(self, port):
        self.port = port
        self.buffer = 102400

    def listen(self):

        sock = socket(AF_INET, SOCK_DGRAM)
        sock.bind(('', self.port))

        while 1:
            data, addr = sock.recvfrom(self.buffer)
            print "Received: " + data
            print "sending to %s" % addr[0]
            print "sending data %s" % data
            time.sleep(0.25)
            #print addr # will tell you what IP address the request came from and port
            sock.sendto(data, (addr[0], addr[1]))
            print "sent"
        sock.close()

if __name__ == "__main__":
    l = Listener(1975)
    l.listen()

现在,从监听器接收响应的客户端(发送者)

from socket import *
from time import sleep
class Sender:
    def __init__(self, server):
       self.port = 1975
       self.server = server
       self.buffer = 102400

    def sendPacket(self, packet):
        sock = socket(AF_INET, SOCK_DGRAM)
        sock.settimeout(10.75)


        sock.sendto(packet, (self.server, int(self.port)))

        while 1:
            print "waiting for response"
            data, addr = sock.recvfrom(self.buffer)
            sock.close()
            return data



if __name__ == "__main__":
        s = Sender("127.0.0.1")
        response = s.sendPacket("Hello, world!")
        print response
于 2008-09-18T18:07:36.473 回答