tudoricc
tudoricc

Reputation: 729

send a file to client using twisted framework

I have been searching on how to transfer a file from a server to a client using the twisted framework for a while now but I haven't found anything useful.

In my case I just want to send an image for a user,it's a chat application and I am storing locally[where i have the server] the image[or so I am trying]

Here is what I did:

from twisted.internet import reactor
from twisted.internet.protocol import Factory , Protocol
class IphoneChat(Protocol):
      def connectionMade(self):
            self.factory.clients.append(self)
      def connectionLost(self , reason):
            self.factory.clients.remove(self)
      def dataReceived(self,data):
            a = data.split(':')
            contor = 0
            command = a[0]
            content = a[1]
            if command == "saveimage":
                personName = a[1]
                contentData = a[2]
                escape = a[3]
                location = "person-images/"+str(personName)+".jpg"
                try:
                    f = open (location,'w+')
                    f.write(contentData)
                except :
                    self.transport.write("error when opening the file")
            elif command == "getimage" :
                picture = a[1]
                extra = a[2]
                location = "person-images/"+picture+".png"
                try:
                    self.transport.write("image:")
                    for bytes in read_bytes_from_file(location) :
                        self.transport.write(bytes)
                    self.transport.write('\r\n')
                except :
                    self.transport.write('no such file\r\n')

factory = Factory()
factory.protocol=IphoneChat
factory.clients = []
reactor.listenTCP(8023,factory)
print "IPhone Chat server started"
reactor.run()

But I am getting a strange behavior at the client[iOS application] and the behaviour is that it is not working.

Something from the iosApp:

                            var binaryData: NSData
                            let string : NSString  = output.componentsSeparatedByString(":")[0] as NSString
                            binaryData = string.dataUsingEncoding(NSUTF8StringEncoding)!

                            var data = UIImage(data: binaryData)
                            self.personImage.image = data
                            self.personImage.hidden = true

Is the problem on the server side or on the client?

Upvotes: 2

Views: 1980

Answers (1)

Anton
Anton

Reputation: 4601

One serious error can immediately be spotted, however I cannot say whether that is the only thing that makes it "not work": Your code expects that when one end does transport.write(x) that then the other end has dataReceived(self, x) called with x being the same. This is not generally the case with TCP. TCP gives a stream of bytes, and you do not have control of how the stream is segmented. See Twisted FAQ. As an example, if one end does transport.write('foobar') then the other end may end up having two calls: first dataReceived('foob') and soon after dataReceived('ar').

What you would need to do, is implement a proper protocol for passing messages over the TCP stream. However, I recommend not rolling your own, but selecting one of the several included with Twisted, or take another clearly specified protocol, such as websockets.

You do seem to end messages with '\r\n', which is a strategy to delimit messages in a byte stream, but note that you will need to do buffering on the receiver to collect complete messages. This is what the LineReceiver protocol included with Twisted does. However, if your read_bytes_from_file() function returns bytes as the name suggest, your protocol will break if the image data includes the bytes '\r\n'

Some general development advice: Don't try to throw together the full implementation with twisted server and iPhone client to start with, and then just find that it doesn't work. You probably have several more errors both on client and server, but that is just to be expected. Write code that you can easily test on the same machine. So, do write a simple testing client to run on the server. Add debug printing or logging to see what is going on, for instance to print what dataReceived(x) gets called with.

Upvotes: 4

Related Questions