AF_UNIX本地数据报套接字的自动命名?
我在unix本地套接字(AF_UNIX地址系列,即而不是UDP)上使用数据报实现一项简单服务。服务器绑定到一个公共地址,它接收请求就好了。不幸的是,当回答回答时,sendto
失败,除非客户端也被绑定。 (常见的错误是Transport endpoint is not connected
)。AF_UNIX本地数据报套接字的自动命名?
绑定到一些随机名称(基于文件系统或抽象)的作品。但我想避免这种情况:我是谁来保证我选择的姓名不会相互冲突?
unix套接字的流模式文档告诉我们,如果他们还没有一个抽象名称,他们将在connect
时间给他们分配一个抽象名称。这种功能是否适用于面向数据报的套接字?
我假设响应你正在运行Linux;我不知道这个建议是否适用于SunOS或任何UNIX。
首先,答案:插座(后)和Connect()或第一的sendto()之前,你可以添加以下代码:
struct sockaddr_un me;
me.sun_family = AF_UNIX;
int result = bind(fd, (void*)&me, sizeof(short));
现在,解释:在unix(7)手册页说,这:
当一个套接字连接,它 还没有在抽象 命名空间的 唯一的地址将自动生成 本地地址。
不幸的是,手册页在于。
检查Linux source code,如果SOCK_PASSCRED在套接字标志中设置,我们看到unix_dgram_connect()只调用unix_autobind()。由于我不知道SOCK_PASSCRED是什么,现在是凌晨1点,我需要寻找另一种解决方案。
检查unix_bind,我注意到,如果传入的大小等于“sizeof(short)”,unix_bind将调用unix_autobind。因此,上面的解决方案。
祝你好运,早上好。
罗布
我不太确定我完全理解你的问题,但这里是我刚写的一个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
的问题是关于Unix套接字,不上网的。 (即,AF_UNIX地址族,而不是AF_INET)。感谢您的回答,我将编辑问题并明确说明。 – 2008-09-18 19:17:16
对不起,感谢您的澄清。 – 2008-09-26 07:00:08
一个反应迟缓的位,但对于任何人发现这个使用谷歌和我一样。罗布亚当的答案帮助我得到了'真正'的答案:只需使用set(级别为SO_SOCKET
,请参阅man 7 unix
)将SO_PASSCRED
设置为1。不需要傻傻的绑定。
我在PHP中使用这一点,但它并没有定义SO_PASSCRED
(愚蠢的PHP)。不过,如果你自己定义它,它仍然有效。在我的电脑上,它的值为16,我认为它的工作非常便携。
的unix(7)手册页我引用了约autobind Unix套接字这样的信息:
如果绑定(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)。
伟大的分析,罗布!非常感谢! 似乎有不同来源的manpages:在工作(一些旧的SuSE),他们明确地限制自动绑定连接效果流套接字。在家里,我有和你一样的句子。 从长远来看,我会记住这是绑定到一个空路径。 – 2008-09-20 13:52:25