Проблема с Twisted python - отправка двоичных данных
Вопрос
То, что я пытаюсь сделать, довольно просто:отправьте файл с клиента на сервер.Сначала клиент отправляет информацию о файле - то есть о его размере.Затем он отправляет сам файл.
Это то, что я делал до сих пор:
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()
Сервер будет выводить только десериализованный объект:
{'размер':183574528L}
Как так вышло?Что случилось с 20 символами из файла, который я хотел отправить?
Если вместо этого использовать посылки "hej" и "wa", я получу их оба (в одном сообщении, а не дважды).
Кто-нибудь?
Решение
Вы перевели свой сервер в необработанный режим с помощью setRawMode(), поэтому обратный вызов rawDataReceived вызывается с входящими данными (не lineReceived).Если вы печатаете полученные данные в rawDataReceived, вы видите все, включая содержимое файла, но когда вы вызываете pickle для десериализации данных, они игнорируются.
Либо вы меняете способ отправки данных на сервер (я бы предложил формат netstring), либо вы передаете содержимое внутри сериализованного объекта pickle и делаете это за один вызов.
self.sendLine(pickle.dumps({"size":filesize, 'content': contents[:20]}))