Проблемы с асинхронным процессором Python, работающим с сокетами AF_UNIX

StackOverflow https://stackoverflow.com/questions/5994521

Вопрос

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

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

 $ socat readline UNIX:/tmp/mysocket

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

Это было полезно?

Решение

Примечание Как указывает другой ответ, когда вы отправляете дейтаграмму, вам необходимо указать получателя.В нынешнем виде ваш 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(), и т. д.

Если вы намеревались использовать 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.Из того, что я могу сказать, вы в основном не можете эффективно обрабатывать сокеты Sock_DGram с Asyncore (без генеракодицетагода или генеракодицетагкода).Кроме того, SOCAT, похоже, не имеет способов работать с доменами SOCK_DGRAM UNIX DOCKETS.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top