美好的一天。
我发送了一个自定义协议,用于通过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
不是一个选项。
答案 0 :(得分:3)
您的读取逻辑似乎不正确。你有......
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);
}
来自QTcpSocket::read(data, MaxSize)
的文档......
从设备读取最多maxSize字节为数据,并返回 读取的字节数
如果您对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.
*/
答案 1 :(得分:1)
如果填充的长度始终是固定的,则只需添加socket->read(2);
即可忽略2个字节。
另一方面,它可能只是冰山一角。你用什么来读写?
答案 2 :(得分:0)
您不应该调用发送三次但只调用一次。要转换为BigEndian,您可以使用Qt functions并将所有内容写入单个缓冲区,并且只调用send一次。这不是你想要的,但我认为这是你需要做的事情,它应该很容易,因为你已经知道你的消息的大小。您也不需要离开Qt世界来发送消息。