Question

J'ai quelques problèmes en utilisant AsynCore avec des sockets AF_UNIX. Ce 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()

Si j'exécute le code

 $ python select_prova.py
 writable
 handle_connect
 handle_write
 handle_close
 $  

Il quitte immédiatement et n'attend pas la lecture et l'écriture. Si je change de code pour forcer la méthode écrivable () pour revenir toujours False, il attend correctement l'entrée et je peux communiquer avec Socat comme celui-ci

 $ socat readline UNIX:/tmp/mysocket

Mais seulement pour la lecture (écrire logiquement ne fonctionne pas parce que Writable () revient False). Y a-t-il une erreur dans mon code ou je ne peux pas gérer les sockets AF_UNIX avec AsynCore / Select ()?

Était-ce utile?

La solution

Noter Comme le souligne l'autre réponse, lorsque vous envoyez un datagramme, vous devez spécifier le récepteur. En l'état, votre testselect La classe ressemble plus à un client qu'à un serveur.

Passez en revue certains d'entre eux asyncore examples Pour trouver un modèle de serveur que vous pouvez copier. La TimeChannel L'exemple est plus proche de ce que vous voulez - changer socket.AF_INET à socket.AF_UNIX et utilisez un chemin de socket pour l'adresse de liaison pour qu'il utilise une prise de domaine UNIX.


Vous définissez socket.SOCK_DGRAM qui indique généralement la création d'une prise INET UDP. Les prises de domaine UNIX sont une forme d'IPC. Tu devrais le changer en socket.SOCK_STREAM, appel self.listen([backlog]), mettre en place handle_accept(), etc.

Si vous aviez l'intention d'utiliser sock_dgram avec af_unix, la raison pour laquelle votre serveur sort est qu'il indique writable dès qu'il a commencé, ce qui provoque handle_write Pour courir, envoyer le paquet contenant 'buffer' immédiatement.

Si vous souhaitez que votre serveur attend qu'il ait reçu un paquet avant de répondre, définissez le tampon handle_connect ou handle_read:

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

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

Maintenant, lorsque vous démarrez votre serveur, il attendra qu'il reçoive un paquet de socat.


J'ai réécrit votre exemple pour travailler plus comme vous entend:

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)

Autres conseils

Votre difficulté peut se résumer au fait que vous utilisez SOCK_DGRAM. D'après ce que je peux dire, vous ne pouvez essentiellement pas gérer efficacement les prises Sock_dgram avec asyncore (non recvfrom ou sendto). De plus, SOCAT ne semble pas avoir de moyen de travailler avec SOCK_DGRAM UNIX DOMAINS.

Les prises SOCK_DGRAM n'ont pas de notion réelle de connexion, elles s'inscrivent donc toujours comme écrivains dans un appel sélectionné. Mais quand tu fais réellement le write Il échouera car vous ne fournissez pas d'adresse de destination.

L'autre réponse a mal la terminologie, mais est fondamentalement correcte. Vous devez utiliser une prise Sock_stream ici.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top