我使用Twisted实现了一个服务器程序。我正在使用basic.lineReceiver
方法dataReceived
来接收来自多个客户端的数据。此外,我正在使用protocol.ServerFactory
来跟踪已连接的客户端。服务器向每个连接的客户端发送一些命令。根据服务器从每个客户端获取的响应,它(服务器)应该执行一些任务。因此,我想到的最佳解决方案是为收到的消息创建一个缓冲区作为python列表,每次服务器端的函数想知道来自客户端的响应时,它们访问缓冲区列表的最后一个元素(该客户)。
事实证明这种方法不可靠。第一个问题是,由于使用了TCP流,有时消息合并(我可以使用分隔符)。其次,收到的消息有时不符合它们的顺序。第三,网络通信似乎太慢,因为当服务器最初尝试访问缓冲列表的最后一个元素时,列表为空(这表明缓冲区上的最后一条消息可能不是对上次发送的响应)命令)。
你能否告诉我在上述问题中使用dataReceived
或其等价物的最佳选择是什么?提前谢谢你。
编辑1:答案 - 虽然我接受了@ Jean-Paul Calderone的答案,因为我当然从中学到了答案,我想在我自己的Twisted'我的文档,我了解到为了避免服务器通信的延迟,应该在dataReceived()或lineReceived()函数的末尾使用return
,这解决了我的问题的一部分。其余的,在答案中解释。
答案 0 :(得分:5)
我使用Twisted实现了一个服务器程序。我使用basic.lineReceiver和dataReceived方法来接收来自多个客户端的数据。
这是一个错误 - 遗憾的是,在许多Twisted协议实现中错误地使用继承作为构建越来越复杂行为的机制而引起的错误。当您使用twisted.protocols.basic.LineReceiver
时,dataReceived
回调不适合您。 LineReceiver.dataReceived
是LineReceiver
的实施细节。您的回调是LineReceiver.lineReceived
。 LineReceiver.dataReceived
看起来可能适合您 - 它不是以下划线或任何东西开头的 - 但事实并非如此。 dataReceived
是LineReceiver
从其传输中接收信息的方式。它是IProtocol
的公共方法之一 - 传输和协议之间的接口,用于解释通过该传输接收的数据。是的,我刚刚说过"公共方法"那里。为了别人的利益,问题在于公开。这很令人困惑,也许并没有尽可能地传达。毫无疑问,这就是Frequently Asked Question的原因。
这种方法结果证明是不可靠的。第一个问题是,由于使用了TCP流,有时消息合并(我可以使用分隔符)。
dataReceived
的使用是发生这种情况的原因。 LineReceiver
已经为您实现了基于分隔符的解析。这就是为什么它被称为" line"接收器 - 它接收由分隔符分隔的行。如果您覆盖lineReceived
而不是dataReceived
,那么无论TCP如何拆分或将它们粉碎在一起,您都可以调用接收到的每一行。
其次,收到的消息有时不符合适当的顺序。
TCP是一种可靠的,有序,面向流的传输。 "有序"表示字节按照发送的顺序到达。换句话说,当你write("x"); write("y")
时,保证接收器将接收" x"在他们收到" y" (他们可能会在recv()
的同一个电话中收到" x"和" y"但如果他们这样做,那么数据肯定是" xy"并且不是" yx&#34 ;;或者他们可能会在两次拨打recv()
时收到两个字节,如果他们这样做,第一个recv()
肯定会被" x"和第二个肯定是" y"而不是相反的方式。)
如果字节看起来的顺序与您发送的顺序不同,那么可能会出现另一个错误,它会使看起来像这样的情况发生 - 但它实际上并非如此。吨。您的平台的TCP堆栈很可能非常接近无错误,特别是它可能没有TCP数据重新排序错误。同样,Twisted的这个区域经过了极好的测试,可能正常工作。这会在您的应用程序代码中留下错误或对您的观察结果进行误解。也许您的代码并不总是将数据附加到列表中,或者数据可能没有按照您预期的顺序发送。
另一种可能性是,您正在讨论数据通过多个单独的TCP连接到达的顺序。 TCP仅通过单个连接进行排序。如果您有两个连接,则很少(如果有)保证数据将通过它们到达的顺序。
第三,网络通信似乎太慢,因为当服务器最初尝试访问缓冲列表的最后一个元素时,列表为空(这表明缓冲区上的最后一条消息可能不是对最后发送的命令)。
什么定义"太慢"?网络和网络一样快。如果这对你来说不够快,那就找一块更胖的铜。听起来你在这里真正的意思是你的服务器有时希望数据在数据实际到达之前到达。但这并不意味着网络速度太慢,这意味着您的服务器没有正确事件驱动。如果您正在检查缓冲区而没有找到您期望的信息,那是因为您在事件发生之前对其进行了检查,并告知您该信息的到达。这就是Twisted拥有所有这些回调方法的原因 - dataReceived
,lineReceived
,connectionLost
等。调用lineReceived
时,这是一个事件通知,告诉您现在发生了一些导致行可用的事情(并且为了方便起见,lineReceived
接受一个参数 - 一个表示现在可用的行的对象。)
如果您有一些代码要在行到达时运行,请考虑将该代码放在lineReceived
方法的实现中。这样,当它运行时(响应正在接收的线路),您可以100%确定您有一条线路可以运行。你也可以确定它会尽快运行(一旦线路到达),但不久就会运行。