Lecture du tampon de socket en utilisant asyncore
Question
Je connais Python pour la première fois (cependant, je programme en Java depuis plusieurs années maintenant) et je travaille sur une simple application réseau basée sur des sockets (juste pour le plaisir). L'idée est que mon code se connecte à un point de terminaison TCP distant, puis écoute toutes les données envoyées du serveur au client et effectue une analyse syntaxique.
Les données envoyées du serveur - > le client est du texte codé UTF-8 et chaque ligne est délimitée par CRLF
( \ x0D \ x0A
). Vous l'avez probablement deviné: l'idée est que le client se connecte au serveur (jusqu'à ce qu'il soit annulé par l'utilisateur), puis lit et analyse les lignes au fur et à mesure de leur arrivée.
J'ai réussi à faire en sorte que cela fonctionne, cependant, je ne suis pas sûr de le faire de la bonne façon. D'où mes vraies questions (code à suivre):
- Est-ce la bonne façon de le faire en Python (c'est-à-dire si simple?)
- Tous les conseils / astuces / ressources utiles (en dehors de la documentation de référence) concernant les tampons /
asyncore
?
Actuellement, les données sont en cours de lecture et de mise en mémoire tampon comme suit:
def handle_read(self):
self.ibuffer = b""
while True:
self.ibuffer += self.recv(self.buffer_size)
if ByteUtils.ends_with_crlf(self.ibuffer):
self.logger.debug("Got full line including CRLF")
break
else:
self.logger.debug("Buffer not full yet (%s)", self.ibuffer)
self.logger.debug("Filled up the buffer with line")
print(str(self.ibuffer, encoding="UTF-8"))
La fonction ByteUtils.ends_with_crlf
vérifie simplement les deux derniers octets du tampon pour \ x0D \ x0A
. La première question est la principale (la réponse est basée sur celle-ci), mais toute autre idée / astuce est appréciée. Merci.
La solution
TCP est un flux, et rien ne garantit que votre tampon ne contiendra pas la fin d’un message ni le début du suivant. Ainsi, la recherche de \ n \ r à la fin du tampon ne fonctionnera pas comme prévu dans toutes les situations. Vous devez vérifier chaque octet dans le flux.
Et je vous recommande fortement d'utiliser Twisted au lieu d'asyncore. Quelque chose comme ça (de mémoire, cela pourrait ne pas fonctionner immédiatement):
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineReceiver
class MyHandler(LineReceiver):
def lineReceived(self, line):
print "Got line:", line
f = protocol.ClientFactory()
f.protocol = MyHandler
reactor.connectTCP("127.0.0.1", 4711, f)
reactor.run()
Autres conseils
C'est encore plus simple: consultez asynchat et ses set_terminator (ainsi que d'autres informations utiles dans ce module). Twisted est un ordre de grandeur plus riche et plus puissant, mais, pour les tâches suffisamment simples, asyncore et asynchat (qui sont conçus pour interagir en douceur) sont en effet très simples à utiliser, comme vous avez commencé à les observer.