python asyncore 使用 AF_UNIX 套接字时出现问题
我在使用 asyncore 和 AF_UNIX 套接字时遇到一些问题。这段代码
import asyncore, socket, os
class testselect(asyncore.dispatcher):
path = '/tmp/mysocket'
def __init__(self):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_UNIX, socket.SOCK_DGRAM)
self.bind(self.path)
self.buffer = 'buffer'
def handle_connect(self):
print 'handle_connect'
pass
def handle_close(self):
print 'handle_close'
if os.path.exists(self.path)
os.remove(self.path)
self.close()
def handle_read(self):
print 'handle_read'
print self.recv(8192)
def writable(self):
print 'writable'
return (len(self.buffer) > 0)
def handle_write(self):
print 'handle_write'
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
client = testselect()
asyncore.loop()
如果我执行代码
$ python select_prova.py
writable
handle_connect
handle_write
handle_close
$
它会立即退出,并且不等待读取和写入。如果我更改代码以强制 writable() 方法始终返回 False
,它会正确等待输入,并且我可以像这样与 socat 进行通信,
$ socat readline UNIX:/tmp/mysocket
但仅用于读取(逻辑上写入不起作用,因为 writable()返回False
)。我的代码是否有错误或者我无法使用 asyncore/select() 管理 AF_UNIX 套接字?
I have some problems using asyncore with AF_UNIX sockets. This code
import asyncore, socket, os
class testselect(asyncore.dispatcher):
path = '/tmp/mysocket'
def __init__(self):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_UNIX, socket.SOCK_DGRAM)
self.bind(self.path)
self.buffer = 'buffer'
def handle_connect(self):
print 'handle_connect'
pass
def handle_close(self):
print 'handle_close'
if os.path.exists(self.path)
os.remove(self.path)
self.close()
def handle_read(self):
print 'handle_read'
print self.recv(8192)
def writable(self):
print 'writable'
return (len(self.buffer) > 0)
def handle_write(self):
print 'handle_write'
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
client = testselect()
asyncore.loop()
If i execute the code
$ python select_prova.py
writable
handle_connect
handle_write
handle_close
$
It quits immediatly, and doesn't wait for read and write. If i change code to force writable() method to return always False
, it wait correctly for input and i can communicate with socat like this
$ socat readline UNIX:/tmp/mysocket
But only for reading (write logically doesn't works because writable() returns False
). Are there error in my code or I can't manage AF_UNIX sockets with asyncore/select() ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
注意 正如其他答案所指出的,当您发送数据报时,您需要指定接收者。就目前情况而言,您的
testselect
类看起来更像是客户端而不是服务器。查看其中一些
asyncore 示例
,找到可以复制的服务器模式。TimeChannel
示例更接近您想要的 - 将socket.AF_INET
更改为socket.AF_UNIX
并使用绑定地址的套接字路径让它使用 UNIX 域套接字。您正在设置
socket.SOCK_DGRAM
,这通常表示创建 UDP INET 套接字。 Unix 域套接字是 IPC 的一种形式。您应该将其更改为socket.SOCK_STREAM
,调用self.listen([backlog])
,实现handle_accept()
等。如果您这样做打算将 SOCK_DGRAM 与 AF_UNIX 一起使用,您的服务器退出的原因是它一启动就指示
writable
,这会导致handle_write
运行,立即发送包含'buffer'
的数据包。如果您希望服务器等到收到数据包后再回复,请在
handle_connect
或handle_read
中设置缓冲区:现在,当您启动服务器时,它会等到收到数据包为止来自
socat
的数据包。我重写了您的示例,使其更像您的预期:
Note As the other answer points out, when you send a datagram you need to specify the receiver. As it stands, your
testselect
class looks more like a client than a server.Review some of these
asyncore examples
to find a server pattern you can copy. TheTimeChannel
example is closer to what you want -- changesocket.AF_INET
tosocket.AF_UNIX
and use a socket path for the bind address to have it use a UNIX domain socket.You're setting
socket.SOCK_DGRAM
which usually indicates creation of a UDP INET socket. Unix domain sockets are a form of IPC. You should change it tosocket.SOCK_STREAM
, callself.listen([backlog])
, implementhandle_accept()
, etc.If you did intend to use SOCK_DGRAM with AF_UNIX, the reason your server exits is that it is indicating
writable
as soon as it's started, which causeshandle_write
to run, sending the packet containing'buffer'
immediately.If you want your server to wait until it's received a packet before replying, set the buffer in
handle_connect
orhandle_read
:Now when you start your server it'll wait until it receives a packet from
socat
.I've rewritten your example to work more like you indend:
您的困难可以归结为您正在使用 SOCK_DGRAM。据我所知,您基本上无法使用 asyncore 有效处理 SOCK_DGRAM 套接字(没有
recvfrom
或sendto
)。此外,socat 似乎没有办法使用 SOCK_DGRAM UNIX 域套接字。SOCK_DGRAM 套接字没有真正的连接概念,因此它们始终在 select 调用中注册为可写。但是当您实际执行
write
时,它将失败,因为您没有提供目标地址。另一个答案有术语错误,但基本上是正确的。这里需要使用 SOCK_STREAM 套接字。
Your difficulty can be boiled down to the fact you're using SOCK_DGRAM. From what I can tell, you basically cannot effectively handle SOCK_DGRAM sockets with asyncore (no
recvfrom
orsendto
). Additionally, socat does not seem to have a way to work with SOCK_DGRAM UNIX domain sockets.SOCK_DGRAM sockets have no real notion of a connection, so they will always register as writeable in a select call. But when you actually do the
write
it will fail because you're not supplying a destination address.The other answer has terminology wrong, but is basically correct. You need to use a SOCK_STREAM socket here.