我在使用 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_INETsocket.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 套接字。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top