Frage

Ich habe einige Probleme bei der Verwendung von Asyncore mit AF_UNIX-Sockets.Dieser 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()

Wenn ich den Code ausführe

 $ python select_prova.py
 writable
 handle_connect
 handle_write
 handle_close
 $  

Es wird sofort beendet und wartet nicht auf Lese- und Schreibvorgänge.Wenn ich den Code ändere, um die Methode writable() zu erzwingen, immer zurückzukehren False, es wartet korrekt auf Eingaben und ich kann auf diese Weise mit socat kommunizieren

 $ socat readline UNIX:/tmp/mysocket

Aber nur zum Lesen (Schreiben funktioniert logischerweise nicht, da writable() zurückkehrt False).Liegt ein Fehler in meinem Code vor oder kann ich AF_UNIX-Sockets nicht mit asyncore/select() verwalten?

War es hilfreich?

Lösung

Notiz Wie aus der anderen Antwort hervorgeht, müssen Sie beim Senden eines Datagramms den Empfänger angeben.So wie es aussieht, Ihr testselect Die Klasse ähnelt eher einem Client als einem Server.

Sehen Sie sich einige davon an asyncore examples um ein Servermuster zu finden, das Sie kopieren können.Der TimeChannel Beispiel ist näher an dem, was Sie wollen – Veränderung socket.AF_INET Zu socket.AF_UNIX und verwenden Sie einen Socket-Pfad für die Bindungsadresse, damit sie einen UNIX-Domänen-Socket verwendet.


Du stellst ein socket.SOCK_DGRAM was normalerweise auf die Erstellung eines UDP-INET-Sockets hinweist.Unix-Domain-Sockets sind eine Form von IPC.Sie sollten es in ändern socket.SOCK_STREAM, Anruf self.listen([backlog]), umsetzen handle_accept(), usw.

Wenn Sie beabsichtigt haben, SOCK_DGRAM mit AF_UNIX zu verwenden, wird Ihr Server aufgrund der Anzeige beendet writable sobald es gestartet ist, was dazu führt handle_write ausführen und das Paket mit dem Inhalt senden 'buffer' sofort.

Wenn Sie möchten, dass Ihr Server wartet, bis er ein Paket empfängt, bevor er antwortet, legen Sie den Puffer fest handle_connect oder handle_read:

    def __init__(self):
        ...
        self.buffer = ''

    def handle_connect(self):
        self.buffer = 'buffer'

Wenn Sie nun Ihren Server starten, wartet er, bis er ein Paket von empfängt socat.


Ich habe Ihr Beispiel so umgeschrieben, dass es eher so funktioniert, wie Sie es sich vorgestellt haben:

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)

Andere Tipps

Ihre Schwierigkeit lässt sich auf die Tatsache zurückführen, dass Sie SOCK_DGRAM verwenden.Soweit ich das beurteilen kann, können Sie SOCK_DGRAM-Sockets mit Asyncore grundsätzlich nicht effektiv verarbeiten (Nr recvfrom oder sendto).Darüber hinaus scheint socat keine Möglichkeit zu haben, mit SOCK_DGRAM UNIX-Domänen-Sockets zu arbeiten.

SOCK_DGRAM-Sockets haben keine wirkliche Vorstellung von einer Verbindung, daher werden sie bei einem SELECT-Aufruf immer als beschreibbar registriert.Aber wenn Sie das tatsächlich tun write Dies schlägt fehl, da Sie keine Zieladresse angeben.

Die andere Antwort hat eine falsche Terminologie, ist aber grundsätzlich richtig.Hier müssen Sie einen SOCK_STREAM-Socket verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top