c++ - QTcpSocket 和 TCP 填充

标签 c++ qt sockets tcp qtcpsocket

美好的一天。

我正在发送一个用于通过 TCP 进行日志记录的自定义协议(protocol),如下所示:

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)显然假设这两个额外的字节实际上是有效负载,这显然弄乱了我的协议(protocol)。

有什么方法可以让我“教”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);

其中“send”声明为(SourceLen 为参数):

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 *)&timestamp, 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);
}

SockQTcpSocket实例,已经连接到主机,addToLog是处理函数。

还需要注意的是,发送端需要在嵌入式系统上运行,因此不能使用QTcpServer

最佳答案

您的读取逻辑似乎不正确。你有...

uint32_t timestamp;
if (Sock.read((char *)&timestamp, 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);
}

来自 QTcpSocket::read(data, MaxSize) 的文档它...

Reads at most maxSize bytes from the device into data, and returns the number of bytes read

如果您对 Sock.read 的调用之一读取了部分数据怎么办?您本质上是丢弃该数据,而不是缓冲它以供下次重用。

假设您有一个适当范围的QByteArray...

QByteArray data;

你的阅读逻辑应该更符合......

/*
 * Append all available data to `data'.
 */
data.append(Sock.readAll());

/*
 * Now repeatedly read/trim messages from data until
 * we have no further complete messages.
 */
while (contains_complete_log_message(data)) {
  auto message = read_message_from_data(data);
  data = data.right(data.size() - message.size());
}

/*
 * At this point `data' may be non-empty but doesn't
 * contain enough data for a complete message.
 */

关于c++ - QTcpSocket 和 TCP 填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45074110/

相关文章:

c++ - 配对可变参数模板(命名元组)

c++ - "Vector iterator not incrementable"错误

c++ - qt QAbstractItemModel 拖放移动项目执行删除/插入

c++ - 获取 QTreeView 的根索引并返回上一级

.net - .NET 中套接字的 Begin* 和 *Async 之间是否存在性能差异?

c - 常规文件上的 Kqueue

c++ - 如何修复 Rational Rhapsody 错误 :"Current value is "VC1 1", but no Visual Studio installation was not found in the directory ""."

c++ - 我如何显式线程化任务?

QtIFW 始终创建注册表项

linux - 如何为 VLAN 嗅探初始化原始套接字