检测原始数据的结束
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 个回答
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
你问的是:
如何让
Twisted
检测原始数据的结束,然后调用rawDataReceived()
?
简单来说,当你开启 raw
模式时,你是在告诉 Twisted 不要 进行检测。
... 让我来解释一下
当你提到在连接中“检测数据的结束”(也就是说,如果你没有在数据结束时关闭连接),你其实是在说一个通常被称为 framing
的概念。
数据分帧是你在进行应用层网络编程时必须考虑的一个主要问题,因为大多数(网络)协议并不保证数据会被分帧到应用层。
让人困惑的是,许多网络协议(TCP就是其中一个最著名的例子)通常但并不总是以与发送时相同的方式将数据呈现给接收方(也就是说,仿佛有分帧,每次 write
都会导致一次 read
- 但这只在使用缓慢和负载低的情况下发生)。由于这种“可能有效也可能无效”的行为,最佳实践是始终明确地添加或构建某种分帧机制。
在TCP/串行/键盘风格的接口中,添加应用层分帧的最常见方法是使用换行符作为帧结束标记,这就是 LineMode
的用途。
在 Twisted 中开启 raw
模式就像是在说“我想自己写分帧”,但我怀疑这真的是你想要的。
相反,你可能想看看 Twisted 提供的一些其他辅助 protocol
s(如 netstring 和 带前缀的消息长度),这些可以为你处理二进制分帧(也可以查看 SO: Twisted 的数据接收中的分段数据,作者是 Twisted 的创始人 Glyph)。