AF_UNIX本地数据报套接字的自动命名?

时间:2008-09-18 17:18:32

标签: unix sockets bind local datagram

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

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

unix套接字的流模式文档告诉我们,如果它们还没有,那么将在connect时为它们分配一个抽象名称。这种功能是否适用于面向数据报的套接字?

4 个答案:

答案 0 :(得分:5)

我引用的unix(7)手册页有关于autobind UNIX套接字的信息:

  

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

这就是Linux内核检查地址长度等于sizeof(short)的原因,因为sa_family_t是一个简短的。 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)。

答案 1 :(得分:4)

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

首先,答案是:在socket()之后和connect()或first sendto()之前,尝试添加以下代码:

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

现在,解释:unix(7)手册页说明了这一点:

  

连接插座时   还没有本地地址a   摘要中的唯一地址   将生成名称空间   自动。

可悲的是,手册页在说谎。

检查Linux source code,我们看到如果在套接字标志中设置了SOCK_PASSCRED,unix_dgram_connect()只调用unix_autobind()。由于我不知道SOCK_PASSCRED是什么,现在凌晨1点,我需要寻找另一个解决方案。

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

祝你好运,早上好。

罗布

答案 2 :(得分:1)

有点迟到的反应,但对于任何人发现这使用谷歌,因为我做了。 Rob Adam的回答帮助我得到了“真正的”答案:只需使用set(级别SO_SOCKET,参见man 7 unix)将SO_PASSCRED设置为1.无需愚蠢的绑定。< / p>

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

答案 3 :(得分:-1)

我不太确定我完全理解你的问题,但这是我刚写的一个echo服务器的数据报实现。您可以看到服务器正在响应客户端发送的相同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