J'ai un service qui utilise une socket de blocage pour recevoir des données. Le problème que j'ai est que je ne sais pas comment fermer correctement le socket s'il attend toujours des données. Vous trouverez ci-dessous un bref aperçu de la façon dont j'ouvre et j'attends des données: je ne veux pas implémenter des délais d'attente car, selon la documentation de python, le socket doit être bloquant pour utiliser makefile.

Je vais peut-être me tromper complètement car je suis nouveau dans la programmation avec des sockets.

ÉDITER:

Il convient de noter que le I ne peut pas modifier le fonctionnement du serveur.

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
reader = s.makefile("rb")
line = reader.readline()
5
Richard 27 sept. 2011 à 20:42

4 réponses

Meilleure réponse

Une solution pour fermer ce socket consiste à demander au serveur de le fermer.

Si le serveur ferme le socket client, le client recevra une erreur de «réinitialisation de la connexion par l'homologue», ce qui peut interrompre la réception bloquante.

Une autre solution serait de ne pas utiliser readline() et de mettre un timeout sur votre socket (une attente indéfinie pourrait attendre .... indéfiniment)

1
Cédric Julien 27 sept. 2011 à 18:17

Comme vous pouvez le voir dans la variété d'autres réponses quelque peu confuses, souvent fragiles ou dangereuses, c'est une question délicate. Heureusement, vous pouvez contourner tous ces problèmes en utilisant des sockets non bloquants à la place. Considérez cette approche (en utilisant Twisted pour plus de simplicité):

from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineOnlyReceiver
from twisted.protocols.policies import TimeoutMixin
from twisted.internet import reactor

class YourClientProtocol(LineOnlyReceiver, TimeoutMixin):
    def connectionMade(self):
        # Initiate the timeout
        self.setTimeout(30)

    def lineReceived(self, line):
        # Reset the countdown
        self.resetTimeout()
        # And process the line somehow
        if line == "great justice":
            print "for the win!"

    def timeoutConnection(self):
        # Report the timeout
        print "Timed out waiting for a line"
        # Drop the connection
        self.transport.loseConnection()

    def connectionLost(self, reason):
        # Let the program complete
        reactor.stop()

# Set up a connection
clientFactory = ClientFactory()
clientFactory.protocol = YourClientProtocol
reactor.connectTCP(HOST, PORT)

# Start the main loop, which can handle timed and 
# network events simultaneously
reactor.run()
0
Jean-Paul Calderone 27 sept. 2011 à 20:30

Je crois que si vous allez de l'avant et le fermez à partir d'un autre fil, le fil qui tentait de le lire reviendra avec une erreur. Si vous n'avez pas plusieurs threads, vous devrez refactoriser pour utiliser le mode non bloquant (option os.O_NONBLOCK lorsque vous ouvrez le socket).

1
wberry 27 sept. 2011 à 19:18

Il existe une solution assez simple. Étant donné un socket et un objet fichier lecteur comme rfile = socket.makefile('rb'), afin de faire rfile.readline() retourner immédiatement lorsque le socket est fermé, vous devez exécuter ce qui suit dans un thread séparé:

socket.shutdown(socket.SHUT_RDWR)
socket.close()

Appeler socket.shutdown() sera faire rfile.readline() retourner un str ou bytes vide, selon la version de Python (2.x ou 3.x respectivement).

5
David Bonnet 7 juil. 2012 à 14:38