【发布时间】:2017-07-13 07:28:53
【问题描述】:
美好的一天。
我正在发送一个自定义协议,用于通过 TCP 进行日志记录,如下所示:
Timestamp (uint32_t -> 4 bytes)
Length of message (uint8_t -> 1 byte)
Message (char -> Length of message)
时间戳转换为 BigEndian 用于传输,一切正常,除了一个小细节:填充
时间戳是自己发送的,但是我的应用程序(在 Ubuntu 下使用 BSD 套接字)不只是发送时间戳(4 个字节),而是自动向消息附加两个字节的填充。
Wireshark 正确识别了这一点并将两个无关字节标记为填充,但是 QTcpSocket(Qt 5.8,mingw 5.3.0)显然假定这两个额外字节实际上是有效负载,这显然会弄乱我的协议。
我有什么方法可以“教”QTcpSocket 忽略填充(就像它应该的那样)或任何方法来摆脱填充?
如果可能的话,我想避免使用整个“创建一个足够大的缓冲区并将整个数据包预先组装在其中,以便一次性发送出去”的方法。
非常感谢。
因为被问到了,所以用来发送数据的代码是:
return
C->sendInt(entry.TS) &&
C->send(&entry.LogLen, 1) &&
C->send(&entry.LogMsg, entry.LogLen);
其中 sendInt 被声明为(Src 是参数):
Src = htonl(Src);
return send(&Src, 4);
“发送”声明为(Source 和 Len 是参数):
char *Src = (char *)Source;
while(Len) {
int BCount = ::send(Sock, Src, Len, 0);
if(BCount < 1) return false;
Src += BCount;
Len -= BCount;
}
return true;
::send 是标准的 BSD 发送函数。
阅读是通过QTcpSocket:
uint32_t timestamp;
if (Sock.read((char *)×tamp, sizeof(timestamp)) > 0)
{
uint8_t logLen;
char message[256];
if (Sock.read((char *)&logLen, sizeof(logLen)) > 0 &&
logLen > 0 &&
Sock.read(message, logLen) == logLen
) addToLog(qFromBigEndian(timestamp), message);
}
Sock是QTcpSocket实例,已经连接到主机,addToLog是处理函数。
另外需要说明的是,发送端需要在嵌入式系统上运行,因此不能使用QTcpServer。
【问题讨论】:
-
请编辑您的问题以显示用于编码/发送数据的代码。使用 TCP 不应该有任何填充。
-
您可能会遇到包括校验和在内的最小以太网帧大小,即 64 字节,您在 Wireshark 中看不到。由于 Wireshark 认识到这一点,我想这就是它的本质,并添加了填充。另一方面,这不应该传播到用户空间,并且填充应该显示在以太网部分。
-
@RolfWinter 这很可能,是的。 Wireshark 确实识别它并将它放在正确的部分,QTcpSocket 是一个搞砸了。
标签: c++ qt sockets tcp qtcpsocket