Проблемы с python asyncore при работе с сокетами AF_UNIX - PullRequest
3 голосов
/ 13 мая 2011

У меня проблемы с использованием асинхронного соединения с сокетами 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
 $  

Он немедленно завершает работу и не ждет чтения и записи.Если я изменяю код, чтобы метод writeable () возвращал всегда False, он корректно ожидает ввода, и я могу общаться с socat следующим образом

 $ socat readline UNIX:/tmp/mysocket

Но только для чтения (логическая запись не работаетпотому что writeable () возвращает False).В моем коде есть ошибка или я не могу управлять сокетами AF_UNIX с помощью asyncore / select ()?

Ответы [ 2 ]

5 голосов
/ 13 мая 2011

Примечание Как указано в другом ответе, при отправке дейтаграммы необходимо указать получателя.В своем нынешнем виде ваш класс testselect больше похож на клиента, чем на сервер.

Просмотрите некоторые из этих asyncore examples, чтобы найти шаблон сервера, который вы можете скопировать.Пример TimeChannel ближе к тому, что вы хотите - измените socket.AF_INET на socket.AF_UNIX и используйте путь сокета для адреса привязки, чтобы он использовал сокет домена UNIX.


You 'заново установите 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:

    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)
1 голос
/ 13 мая 2011

Ваша трудность может быть сведена к тому факту, что вы используете SOCK_DGRAM.Из того, что я могу сказать, вы в принципе не можете эффективно обрабатывать сокеты SOCK_DGRAM с асинхронностью (без recvfrom или sendto).Кроме того, у socat, похоже, нет способа работать с доменными сокетами SOCK_DGRAM UNIX.

Сокеты SOCK_DGRAM не имеют реального представления о соединении, поэтому они всегда регистрируются как доступные для записи в вызове select.Но когда вы на самом деле делаете write, он потерпит неудачу, потому что вы не указываете адрес назначения.

Другой ответ неверен в терминологии, но в основном верен.Вам нужно использовать сокет SOCK_STREAM здесь.

...