Pregunta

Tengo algunos problemas al usar asyncore con sockets AF_UNIX.este codigo

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

Si ejecuto el código

 $ python select_prova.py
 writable
 handle_connect
 handle_write
 handle_close
 $  

Se cierra inmediatamente y no espera lectura ni escritura.Si cambio el código para forzar que el método writable() regrese siempre False, espera correctamente la entrada y puedo comunicarme con socat de esta manera

 $ socat readline UNIX:/tmp/mysocket

Pero sólo para leer (escribir lógicamente no funciona porque writable() devuelve False).¿Hay un error en mi código o no puedo administrar los sockets AF_UNIX con asyncore/select()?

¿Fue útil?

Solución

Nota Como señala la otra respuesta, cuando envía un datagrama debe especificar el receptor.Tal como está, su testselect La clase se parece más a un cliente que a un servidor.

Revisa algunos de estos asyncore examples para encontrar un patrón de servidor que pueda copiar.El TimeChannel El ejemplo está más cerca de lo que quieres: cambiar. socket.AF_INET a socket.AF_UNIX y use una ruta de socket para la dirección de enlace para que use un socket de dominio UNIX.


estas configurando socket.SOCK_DGRAM que generalmente indica la creación de un socket UDP INET.Los sockets de dominio Unix son una forma de IPC.Deberías cambiarlo a socket.SOCK_STREAM, llamar self.listen([backlog]), implementar handle_accept(), etc.

Si tenía la intención de utilizar SOCK_DGRAM con AF_UNIX, la razón por la que su servidor sale es porque está indicando writable tan pronto como comienza, lo que causa handle_write para ejecutarse, enviando el paquete que contiene 'buffer' inmediatamente.

Si desea que su servidor espere hasta recibir un paquete antes de responder, configure el búfer en handle_connect o handle_read:

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

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

Ahora, cuando inicie su servidor, esperará hasta recibir un paquete de socat.


He reescrito tu ejemplo para que funcione más como lo deseas:

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)

Otros consejos

Tu dificultad puede reducirse al hecho de que estás usando SOCK_DGRAM.Por lo que puedo decir, básicamente no puedes manejar efectivamente los sockets SOCK_DGRAM con asyncore (no recvfrom o sendto).Además, socat no parece tener una manera de trabajar con sockets de dominio SOCK_DGRAM UNIX.

Los sockets SOCK_DGRAM no tienen una noción real de una conexión, por lo que siempre se registrarán como grabables en una llamada de selección.Pero cuando realmente haces lo write fallará porque no estás proporcionando una dirección de destino.

La otra respuesta tiene una terminología incorrecta, pero es básicamente correcta.Necesitas usar un socket SOCK_STREAM aquí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top