在Twisted处理大尺寸包

时间:2018-01-20 20:06:32

标签: python multithreading tcp twisted serve

我目前正在构建一个TCP服务器(该服务器将由我的公司使用,因此它必须处于高产量水平)

我的要求是:

  1. 服务器速度很快(它可以同时处理大量请求,因为我们的客户经常发送大文件,这会产生瓶颈)。

  2. 服务器易于维护。

  3. 同时支持尽可能多的用户。

  4. 服务器将是TCP服务器,因为它接收我们公司开发的协议消息,我需要自己解析它。

  5. 在检查选项之后,我选择了Python Twisted,因为他似乎满足了第一个要求(因为他在Python中,然后第二个需求就自己解决了。)

    在阅读Twisted的文档后,我想到了一个问题,我还没有找到一个优雅的答案,我的客户向我发送了相当大的数据包,我根据这些数据包中的子序列做出决定。

    让我们说如果我得到1000个全部为0的第一个字节,然后是另外5,000个字节,所有这些都是0x10,我将发回" Hello world"如果我得到2000字节,所有这些都是0x50我将回答"大家好"。

    我对Twisted的问题是数据最终会出现在" protocol.Protocol"并使用" dataReceived(自我,数据)"函数,这个瞬间是一次性的瞬间,这意味着如果我第一次只得到一些字节而我第二次得到剩下的字节我就没有了从第一次起保存数据......

    我无法将数据保存在protocol.Factory中,因为我会同时与多个客户端通信,然后一个人将使用另一个客户端的数据,因为我不能使用Globals。

    我很确定我不是第一个遇到这个问题的人,我已经看过几个在线解决方案,包括重新实施" protocol.Protocol"他们真的不优雅..

    有没有简单而优雅的方法来解决这个问题? (解决方案必须优雅,因为我添加了多线程,因为我回馈给客户端的东西远远超过" Hello World"我不想阻止服务器)

    顺便说一下,如果有经验的人可以推荐一个比Twisted更好的解决方案,我非常高兴。

    谢谢

    阳子

1 个答案:

答案 0 :(得分:1)

听起来你需要维持一些连接状态。这是您可以存储并仍然使用此类协议的最低金额。您的协议类应该在每个连接上实例化一次,因此您应该能够使用该类的属性来存储zeros_receivedtwos_received之类的内容。

def dataReceived(self, data):
    if self.zeros_received != 1000:
        for x, b in enumerate(data):
            if b != 0x00:
                # Handle unexpected byte error
            self.zeros_received += 1

            if self.zeros_received == 1000:
                break

    if self.twos_received != 5000:
        for b in data[x+1:]:
            if b != 0x10:
                # handle unexpected byte error
            self.twos_received += 1

            if self.twos_received == 5000:
                break

   # send hello...

更简单的解决方案是缓冲来自客户端的数据,然后阻止(连接超时),直到您收到前6k字节为止。我要小心过早优化。您现在假设这将是您的瓶颈,但通常您的假设可能是错误的。首先实现一个天真的解决方案(使用缓冲读取器),然后对速度/内存使用情况进行基准测试,看看实际需要改进的地方。

def dataReceived(self, data):
    self.data += data

    if len(self.data) >= 6000:
        assert all(lambda b: b == 0x00, self.data[:1000]), 'expected 0x00'
        assert all(lambda b: b == 0x10, self.data[1000:6000]), 'expected 0x10'

        # send hello