Domanda

Ho alcuni problemi con l'utilizzo di asyncore con i socket AF_UNIX.Questo codice

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()

Se eseguo il codice

 $ python select_prova.py
 writable
 handle_connect
 handle_write
 handle_close
 $  

Si chiude immediatamente e non attende la lettura e la scrittura.Se cambio il codice per forzare il metodo scrivibile() a restituire sempre False, attende correttamente l'input e posso comunicare con socat in questo modo

 $ socat readline UNIX:/tmp/mysocket

Ma solo per la lettura (scrivere logicamente non funziona perché writable() restituisce False).Ci sono errori nel mio codice o non riesco a gestire i socket AF_UNIX con asyncore/select() ?

È stato utile?

Soluzione

Nota Come sottolinea l'altra risposta, quando invii un datagramma devi specificare il destinatario.Così com'è, il tuo testselect La classe assomiglia più a un client che a un server.

Rivedi alcuni di questi asyncore examples per trovare un modello di server che puoi copiare.IL TimeChannel l'esempio è più vicino a ciò che desideri: cambiare socket.AF_INET A socket.AF_UNIX e utilizzare un percorso socket per l'indirizzo di collegamento in modo che utilizzi un socket di dominio UNIX.


Stai ambientando socket.SOCK_DGRAM che di solito indica la creazione di un socket INET UDP.I socket di dominio Unix sono una forma di IPC.Dovresti cambiarlo in socket.SOCK_STREAM, chiamata self.listen([backlog]), strumento handle_accept(), eccetera.

Se intendevi utilizzare SOCK_DGRAM con AF_UNIX, il motivo per cui il tuo server esce è che indica writable non appena viene avviato, il che provoca handle_write da eseguire, inviando il pacchetto contenente 'buffer' subito.

Se vuoi che il tuo server aspetti finché non riceve un pacchetto prima di rispondere, imposta il buffer handle_connect O handle_read:

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

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

Ora quando avvii il tuo server attenderà finché non riceverà un pacchetto da socat.


Ho riscritto il tuo esempio per funzionare più come intendi tu:

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)

Altri suggerimenti

La tua difficoltà può essere bollita dal fatto che stai usando Sock_dgram.Da ciò che posso dire, in pratica non è possibile gestire efficacemente le prese SOCK_DGRAM con Asyncore (nessun recvfrom o sendto).Inoltre, SOCAT non sembra avere un modo per lavorare con i socket di dominio SOCK_DGRAM UNIX.

Sock_dgram Le prese non hanno alcuna nozione reale di una connessione, quindi si registrano sempre come scrivibili in una chiamata selezionata.Ma quando effettivamente fai il write, fallirà perché non stai fornendo un indirizzo di destinazione.

L'altra risposta ha la terminologia errata, ma è sostanzialmente corretta.È necessario utilizzare una presa SOCK_STREAM qui.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top