【问题标题】:How to use dataReceived in Twisted?如何在 Twisted 中使用 dataReceived?
【发布时间】:2014-11-20 15:12:19
【问题描述】:

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

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

【问题讨论】:

    标签: python twisted


    【解决方案1】:

    我已经使用 Twisted 实现了一个服务器程序。我正在使用带有 dataReceived 方法的 basic.lineReceiver 来接收来自多个客户端的数据。

    这是一个错误——不幸的是,在 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% 确定您有一条线路可以操作。您还可以确保它会尽快运行(只要线路到达),但不会更早。

    【讨论】:

    • 感谢您的回答。关于接收消息的顺序,如果我在客户端使用python socket库,通过写socket.recv()或者socket.send,会不会导致连接不是TCP?
    • 如果你使用socket.socket()(不带参数)创建套接字,它是一个TCP套接字(只能用于建立TCP连接)。此外,reactor.listenTCP 创建了一个只能接受 TCP 连接的服务器。
    • @Jean-PaulCalderone 我想从 syslog 中逐行发送数据,但是 lineReceived 总是给我接收到的字节所需的 str 我怎么能覆盖它,它在 dataReceived 中工作正常。
    • @Root 听起来您的字符串类型有问题。虽然这听起来与这个问题有关,但我认为你应该打开一个包含所有细节的新问题 (sscce.org),我相信你会在那里得到一个很好的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-29
    • 1970-01-01
    相关资源
    最近更新 更多