python asyncore 使用 AF_UNIX 套接字时出现问题
-
13-11-2019 - |
题
我在使用 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 套接字?
解决方案
笔记 正如另一个答案指出的那样,当您发送数据报时,您需要指定接收者。就目前情况而言,您的 testselect
类看起来更像是客户端而不是服务器。
查看其中一些 asyncore examples
找到可以复制的服务器模式。这 TimeChannel
例子更接近你想要的——改变 socket.AF_INET
到 socket.AF_UNIX
并使用绑定地址的套接字路径以使其使用 UNIX 域套接字。
你正在设置 socket.SOCK_DGRAM
这通常表示创建 UDP INET 套接字。Unix 域套接字是 IPC 的一种形式。你应该将其更改为 socket.SOCK_STREAM
, , 称呼 self.listen([backlog])
, , 实施 handle_accept()
, , ETC。
如果您确实打算将 SOCK_DGRAM 与 AF_UNIX 一起使用,那么您的服务器退出的原因是它表明 writable
一旦开始,这会导致 handle_write
运行,发送包含 'buffer'
立即地。
如果您希望服务器等到收到数据包后再回复,请将缓冲区设置为 handle_connect
或者 handle_read
:
def __init__(self):
...
self.buffer = ''
def handle_connect(self):
self.buffer = 'buffer'
现在,当您启动服务器时,它会等待,直到收到来自的数据包 socat
.
我重写了您的示例,使其更像您的预期:
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_STREAM)
self.set_reuse_addr()
self.bind(self.path)
self.listen(5)
def handle_accept(self):
client = self.accept()
if client is None:
pass
else:
handler = testhandler(*client)
class testhandler(asyncore.dispatcher_with_send):
def __init__(self, sock, addr):
asyncore.dispatcher_with_send.__init__(self, sock)
self.addr = addr
self.buffer = 'greetings'
def handle_read(self):
print self.recv(8192)
def writable(self):
return (len(self.buffer) > 0)
def handle_write(self):
self.send(self.buffer)
self.buffer = ''
def handle_close(self):
self.close()
server = testselect()
try:
asyncore.loop()
finally:
if os.path.exists(testselect.path):
os.unlink(testselect.path)
其他提示
您的困难可以归结为您正在使用 SOCK_DGRAM。据我所知,您基本上无法使用 asyncore 有效处理 SOCK_DGRAM 套接字(不 recvfrom
或者 sendto
)。此外,socat 似乎没有办法使用 SOCK_DGRAM UNIX 域套接字。
SOCK_DGRAM 套接字没有真正的连接概念,因此它们始终在 select 调用中注册为可写。但当你真正做的时候 write
它将失败,因为您没有提供目标地址。
另一个答案有术语错误,但基本上是正确的。这里需要使用 SOCK_STREAM 套接字。