Problème avec Twisted Python - envoi de données binaires
Question
Ce que j'essaie de faire est assez simple: envoyer un fichier de client à serveur. Tout d’abord, le client envoie des informations sur le fichier - sa taille. Ensuite, il envoie le fichier réel.
C’est ce que j’ai fait jusqu’à présent:
Server.py
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineReceiver
import pickle
import sys
class Echo(LineReceiver):
def connectionMade(self):
self.factory.clients.append(self)
self.setRawMode()
def connectionLost(self, reason):
self.factory.clients.remove(self)
def lineReceived(self, data):
print "line", data
def rawDataReceived(self, data):
try:
obj = pickle.loads(data)
print obj
except:
print data
#self.transport.write("wa2")
def main():
"""This runs the protocol on port 8000"""
factory = protocol.ServerFactory()
factory.protocol = Echo
factory.clients = []
reactor.listenTCP(8000,factory)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
Client.py
import pickle
from twisted.internet import reactor, protocol
import time
import os.path
from twisted.protocols.basic import LineReceiver
class EchoClient(LineReceiver):
def connectionMade(self):
file = "some file that is a couple of megs"
filesize = os.path.getsize(file)
self.sendLine(pickle.dumps({"size":filesize}))
f = open(file, "rb")
contents = f.read()
print contents[:20]
self.sendLine(contents[:20])
f.close()
# self.sendLine("hej")
# self.sendLine("wa")
def connectionLost(self, reason):
print "connection lost"
class EchoFactory(protocol.ClientFactory):
protocol = EchoClient
def clientConnectionFailed(self, connector, reason):
print "Connection failed - goodbye!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost - goodbye!"
reactor.stop()
# this connects the protocol to a server runing on port 8000
def main():
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
Le serveur produira uniquement l'objet désérialisé:
{'taille': 183574528L}
Comment ça se fait? Qu'advient-il des 20 caractères du fichier que je voulais envoyer?
Si vous utilisez les " hej " et " wa " envoie à la place, je les aurai tous les deux (dans le même message, pas deux fois).
Quelqu'un?
La solution
Vous avez défini votre serveur en mode brut avec setRawMode (). Le rappel rawDataReceived est donc appelé avec les données entrantes (et non par lineReceived). Si vous imprimez les données que vous recevez dans rawDataReceived, vous voyez tout, y compris le contenu du fichier, mais lorsque vous appelez pickle pour désérialiser les données, elles sont ignorées.
Soit vous modifiez la manière dont vous envoyez les données au serveur (je suggérerais le format netstring), soit vous transmettez le contenu à l'intérieur de l'objet sérialisé pickle et vous le faites en un seul appel.
self.sendLine(pickle.dumps({"size":filesize, 'content': contents[:20]}))