使用Twisted框架将文件发送给客户端

2 投票
1 回答
1970 浏览
提问于 2025-04-20 20:49

我一直在寻找如何通过twisted框架将文件从服务器传输到客户端的方法,但一直没有找到有用的信息。

在我的情况下,我只是想给用户发送一张图片,这是一个聊天应用程序,我在本地[也就是我有服务器的地方]存储这张图片[或者说我正在尝试这么做]

这是我做的:

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

但是我在客户端[iOS应用]遇到了奇怪的情况,表现就是它没有正常工作。

这是iOS应用的一些内容:

                            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

问题出在服务器端还是客户端呢?

1 个回答

4

有一个明显的错误,不过我不能确定这是否是导致它“无法工作”的唯一原因:你的代码期望在一端调用 transport.write(x) 时,另一端会调用 dataReceived(self, x),而且 x 是相同的。这在TCP中并不总是这样。TCP提供的是一个字节流,你无法控制这个流是如何被分割的。你可以查看Twisted常见问题解答。举个例子,如果一端调用 transport.write('foobar'),那么另一端可能会接收到两次调用:第一次是 dataReceived('foob'),然后很快又是 dataReceived('ar')

你需要做的是实现一个合适的协议来在TCP流中传递消息。不过,我建议不要自己从头开始写,而是选择Twisted中包含的几种协议之一,或者使用其他明确规定的协议,比如websockets。

你似乎是用 '\r\n' 来结束消息,这是一种在字节流中分隔消息的策略,但请注意,你需要在接收端进行缓冲,以便收集完整的消息。这就是Twisted中包含的 LineReceiver 协议所做的事情。不过,如果你的 read_bytes_from_file() 函数如名字所示返回的是字节数据,那么如果图像数据中包含 '\r\n',你的协议就会出问题。

一些一般性的开发建议:一开始不要试图把Twisted服务器和iPhone客户端的完整实现拼凑在一起,然后发现它无法工作。你可能在客户端和服务器上都有更多的错误,但这都是正常的。写一些可以在同一台机器上轻松测试的代码。所以,确实要写一个简单的测试客户端在服务器上运行。添加调试打印或日志记录,以便查看发生了什么,比如打印 dataReceived(x) 被调用时的参数。

撰写回答