2008-09-18 63 views
4

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

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

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

回答

4

我假设响应你正在运行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。因此,上面的解决方案。

祝你好运,早上好。

罗布

+0

伟大的分析,罗布!非常感谢! 似乎有不同来源的manpages:在工作(一些旧的SuSE),他们明确地限制自动绑定连接效果流套接字。在家里,我有和你一样的句子。 从长远来看,我会记住这是绑定到一个空路径。 – 2008-09-20 13:52:25

-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 
+0

的问题是关于Unix套接字,不上网的。 (即,AF_UNIX地址族,而不是AF_INET)。感谢您的回答,我将编辑问题并明确说明。 – 2008-09-18 19:17:16

+0

对不起,感谢您的澄清。 – 2008-09-26 07:00:08

0

一个反应迟缓的位,但对于任何人发现这个使用谷歌和我一样。罗布亚当的答案帮助我得到了'真正'的答案:只需使用set(级别为SO_SOCKET,请参阅man 7 unix)将SO_PASSCRED设置为1。不需要傻傻的绑定。

我在PHP中使用这一点,但它并没有定义SO_PASSCRED(愚蠢的PHP)。不过,如果你自己定义它,它仍然有效。在我的电脑上,它的值为16,我认为它的工作非常便携。

3

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)。