Problema con Python retorcido: envío de datos binarios
Pregunta
Lo que intento hacer es bastante simple: enviar un archivo del cliente al servidor. Primero, el cliente envía información sobre el archivo, el tamaño que tiene. Luego envía el archivo real.
Esto es lo que he hecho hasta ahora:
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()
El servidor solo generará el objeto deserializado:
{'size': 183574528L}
¿Cómo es que? ¿Qué pasó con los 20 caracteres del archivo que quería enviar?
Si usa el " hej " y "wa" envía en su lugar, los recibiré a ambos (en el mismo mensaje, no dos veces).
¿Alguien?
Solución
Ha configurado su servidor en modo sin procesar con setRawMode (), por lo que la devolución de llamada rawDataReceived se llama con los datos entrantes (no lineReceived). Si imprime los datos que recibe en rawDataReceived, verá todo, incluido el contenido del archivo, pero cuando llama a pickle para deserializar los datos, se ignora.
O cambia la forma en que envía los datos al servidor (sugeriría el formato de red) o pasa el contenido dentro del objeto serializado en escabeche, y lo hace en una sola llamada.
self.sendLine(pickle.dumps({"size":filesize, 'content': contents[:20]}))