如何使用Twisted中收到的数据? - python

我已经使用Twisted实现了服务器程序。我正在将basic.lineReceiver与方法dataReceived一起使用,以从多个客户端接收数据。另外,我正在使用protocol.ServerFactory来跟踪连接的客户端。服务器向每个连接的客户端发送一些命令。根据服务器从每个客户端获得的响应,它(服务器)应执行一些任务。因此,我想到的最好的解决方案是为接收到的消息作为python列表创建一个缓冲区,并且每当服务器端的函数希望了解客户端的响应时,它们都会访问缓冲区列表的最后一个元素(该客户的)。
事实证明这种方法不可靠。第一个问题是,由于使用了TCP流传输,因此有时消息会合并(为此我可以使用定界符)。其次,收到的消息有时不按其适当的顺序排列。第三,网络通信似乎太慢,因为当服务器最初尝试访问缓冲列表的最后一个元素时,列表为空(这表明缓冲区上的最后一条消息可能不是对最后发送的消息的响应)命令)。
您能告诉我在上述问题中使用dataReceived或其等效项的最佳方法是什么?先感谢您。

编辑1:答案-虽然我肯定会从中接受@ Jean-Paul Calderone的答案,但是我想在自己对Twisted文档的研究中补充一点,我了解到为了避免服务器通信的延迟,应该在dataReceived()或lineReceived()函数的末尾使用return,这解决了部分问题。其余的,在答案中进行了解释。

python大神给出的解决方案

我已经使用Twisted实现了服务器程序。我正在将basic.lineReceiver与dataReceived方法一起使用,以从多个客户端接收数据。

这是一个错误-不幸的是,在Twisted的许多协议实现中,错误地使用继承作为建立越来越复杂的行为的机制,导致了这种错误。使用twisted.protocols.basic.LineReceiver时,dataReceived回调不适合您。 LineReceiver.dataReceivedLineReceiver的实现细节。您的回调是LineReceiver.lineReceivedLineReceiver.dataReceived看起来可能适合您-它不是以下划线或任何内容开头-并非如此。 dataReceivedLineReceiver从其传输中接收信息的方式。它是IProtocol的公共方法之一-传输与解释通过该传输接收的数据的协议之间的接口。是的,我刚才在那说了“公共方法”。麻烦的是,这是为了别人的利益而公开。这令人困惑,也许无法很好地传达出来。毫无疑问,这就是为什么它是Frequently Asked Question的原因。

事实证明这种方法不可靠。第一个问题是,由于使用了TCP流传输,因此有时消息会合并(为此我可以使用定界符)。

使用dataReceived就是这种情况的原因。 LineReceiver已经为您实现了基于定界符的解析。这就是为什么它被称为“行”接收器-它接收由定界符分隔的行的原因。如果您覆盖lineReceived而不是dataReceived,那么无论TCP如何拆分或将它们粉碎在一起,您都会被称为收到的每一行。

其次,收到的消息有时不按其适当的顺序排列。

TCP是一种可靠的,有序的,面向流的传输。 “有序”是指字节以与发送时相同的顺序到达。换句话说,当您write("x"); write("y")时,可以确保接收方在收到“ y”之前先收到“ x”(它们可以在对recv()的同一调用中收到“ x”和“ y”,但是如果这样做,数据肯定是“ xy”而不是“ yx”;或者它们可能在两次调用recv()的过程中接收到两个字节,如果这样做,第一个recv()肯定是“ x”,第二个肯定是“ y”,而不是相反)。

如果字节的到达顺序似乎与发送时的顺序不同,则可能是某个地方出现了另一个错误,使它看起来像是在发生这种情况-但实际上并非如此。您平台的TCP堆栈很可能几乎没有错误,特别是它可能没有TCP数据重新排序错误。同样,Twisted的这一区域也经过了充分的测试,可能正常工作。这会在您的应用程序代码中留下一个错误或对您的观察结果的误解。也许您的代码并不总是将数据追加到列表中,或者数据未按预期的顺序发送。

另一种可能性是您正在谈论数据通过多个单独的TCP连接到达的顺序。 TCP仅通过单个连接进行订购。如果您有两个连接,则几乎没有(如果有的话)有关数据通过它们到达的顺序的保证。

第三,网络通信似乎太慢,因为当服务器最初尝试访问缓冲列表的最后一个元素时,列表为空(这表明缓冲区上的最后一条消息可能不是对最后发送的消息的响应)命令)。

什么定义“太慢”?网络与网络一样快。如果那还不够快,那就找一块更粗的铜。听起来您在这里真正的意思是您的服务器有时期望数据在实际到达之前已经到达。但这并不意味着网络速度太慢,这意味着您的服务器没有正确地由事件驱动。如果您正在检查缓冲区而未找到所需的信息,那是因为您在事件发生之前检查了缓冲区,该事件会通知您该信息的到来。这就是Twisted具有所有这些回调方法的原因-dataReceivedlineReceivedconnectionLost等。调用lineReceived时,这是一个事件通知,告诉您现在发生了某些事情,导致一行可用(为了方便起见,lineReceived接受一个参数-表示现在可用的行的对象)。

如果您有一些要在一行到达时运行的代码,请考虑将该代码放入lineReceived方法的实现中。这样,当它运行时(响应收到一条线),您可以100%确保有一条线可以进行操作。您还可以确保它会尽快运行(只要线路到达),但不会尽快运行。