views:

925

answers:

1

What I'm trying to do is fairly simple: send a file from client to server. First, the client sends information about the file - the size of it that is. Then it sends the actual file.

This is what I've done so far:

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()

The server will only output the deserialized object:

{'size': 183574528L}

How come? What happend to the 20 chars from the file I wanted to send?

If use the "hej" and "wa" sends instead, I will get them both (in the same message, not twice).

Somebody?

+5  A: 

You've set your server to raw mode with setRawMode(), so the callback rawDataReceived is being called with the incoming data (not lineReceived). If you print the data you receive in rawDataReceived, you see everything including the file content, but as you call pickle to deserialize the data, it's being ignored.

Either you change the way you send data to the server (I would suggest the netstring format) or you pass the content inside the pickle serialized object, and do this in one call.

self.sendLine(pickle.dumps({"size":filesize, 'content': contents[:20]}))
Agathe
One weird thing though. If I write the data I received to disk, it'll always be 2 bytes more than the file sent. It doesn't matter what file, how big or small it is. The result will always be appended by 2 bytes. Got any clue what that might be?
quano
You can find the files here:http://files.getdropbox.com/u/608462/simpleclient.pyhttp://files.getdropbox.com/u/608462/simpleserv.py
quano
Of course it's two bytes longer. You're using sendLine to send an arbitrarily large binary data blob. You're also buffering the entire thing into memory and blocking the protocol for file IO after receiving it all, then not resetting your server into line mode. You've still got a lot of code to remove before this is correct. :)
Dustin
Which one of those is making it 2 bytes longer? sendLine? I noticed the two bytes are carriage return and new line.Otherwise, yeah, this is hardly correct atm considering the blocking and not going into line mode etc. I just didn't bother with that, just wanted to get the one file sending to work properly.
quano