检测原始数据的结束

2 投票
2 回答
563 浏览
提问于 2025-04-18 07:31

Twisted 有两种接收数据的模式:一种是行模式(Line Mode),另一种是原始模式(Raw Mode)。我们可以通过 setRawMode()setLineMode() 这两个函数在这两种模式之间切换。

在行模式下,系统会检测到行的结束,然后调用 lineReceived() 这个函数。

根据 Twisted 的文档

def rawDataReceived(self, data):

当接收到原始数据时,重写这个函数。

那么 Twisted 是怎么检测到原始数据的结束,并调用 rawDataReceived() 呢?

编辑:

我会补充一些内容来完善我的问题。

我正在使用这个 Qt 函数来向 Twisted 服务器发送数据:

qint64 QIODevice::write(const QByteArray & byteArray)

我原以为调用 write() 两次意味着 Twisted 服务器也会触发 rawDataReceived() 函数两次。

write( "raw1" );
write( "raw2" ); 

但是数据却是一并接收的。

2 个回答

3

Twisted并不会自动判断原始数据的结束。它只是每当收到数据时,就会调用rawDataReceived这个函数。

下面是Twisted代码中相关的部分。 (protocols/basic.py)

def dataReceived(self, data):
    """
    Protocol.dataReceived.
    Translates bytes into lines, and calls lineReceived (or
    rawDataReceived, depending on mode.)
    """
    if self._busyReceiving:
        self._buffer += data
        return

    try:
        self._busyReceiving = True
        self._buffer += data
        while self._buffer and not self.paused:
            if self.line_mode:
                ....
            else:
                data = self._buffer
                self._buffer = b''
                why = self.rawDataReceived(data) # <--------
                if why:
                    return why
    finally:
        self._busyReceiving = False
5

你问的是:

如何让 Twisted 检测原始数据的结束,然后调用 rawDataReceived()

简单来说,当你开启 raw 模式时,你是在告诉 Twisted 不要 进行检测。

... 让我来解释一下

当你提到在连接中“检测数据的结束”(也就是说,如果你没有在数据结束时关闭连接),你其实是在说一个通常被称为 framing 的概念。

数据分帧是你在进行应用层网络编程时必须考虑的一个主要问题,因为大多数(网络)协议并不保证数据会被分帧到应用层

让人困惑的是,许多网络协议(TCP就是其中一个最著名的例子)通常但并不总是以与发送时相同的方式将数据呈现给接收方(也就是说,仿佛有分帧,每次 write 都会导致一次 read - 但这只在使用缓慢和负载低的情况下发生)。由于这种“可能有效也可能无效”的行为,最佳实践是始终明确地添加或构建某种分帧机制。

在TCP/串行/键盘风格的接口中,添加应用层分帧的最常见方法是使用换行符作为帧结束标记,这就是 LineMode 的用途。

在 Twisted 中开启 raw 模式就像是在说“我想自己写分帧”,但我怀疑这真的是你想要的。

相反,你可能想看看 Twisted 提供的一些其他辅助 protocols(如 netstring带前缀的消息长度),这些可以为你处理二进制分帧(也可以查看 SO: Twisted 的数据接收中的分段数据,作者是 Twisted 的创始人 Glyph)。

撰写回答