如何通过UDP接收QByteArray并将其解析为位字段结构?
How to receive and parse a QByteArray over UDP into a structure of bit fields?
有 2 个位字段结构组合成一个结构。以前,当结构的总大小允许时,它会在 uint64 中通过联合进行联合。现在结构的大小变大了,我把它从服务器传递给客户端的QByteArray,现在接收和解析有问题。
正常人如何做对?你仍然可以举个例子,我会很高兴的!
客户端
QDataStream stmFrom( &buffer, QIODevice::ReadWrite );
QTextStream cdl( & log );
for(int i(0); i < 5; i++)
{
stru m;// union in it is a structure with bit fields and uint64
stmFrom >> m.all; // from QByteArray to uint64
cdl << m.all;// write to file
cdl << "n";
}
我认为这对我来说是晦涩而低级的解决方案。据我所知,低级解决方案通常更难维护、阅读和调试。
序列化/反序列化已被许多开发人员/社区多次实现。我认为最好使用一个常见的、众所周知的、无错误的序列化库。
例如,https://github.com/USCiLab/cereal 是一个不错的选择,只需让它为您序列化和反序列化,或者只使用 QDataStream。
若要防止主机和客户端计算机字节序之间的冲突,应使用portable_archive
或QDataStream
。
此外,如果您使用的是UDP并且您的数据很重要,则应添加校验和部分,因为UDP上的损失机会。
如果您使用的是TCP,则需要将消息的长度添加到消息中,因为它是面向流的结构。
示例我正在演示基本的,丑陋但更高级别的实现
#include <QDataStream>
#include <QCoreApplication>
#include <QDebug>
template< int MsgId , typename T>
struct msg
{
int id() { return msg_id; }
T data;
private:
template< int Id , typename Type >
friend QDataStream& operator<<( QDataStream& out , const msg<Id , Type>& );
template< int Id , typename Type >
friend QDataStream& operator>>( QDataStream& out , msg<Id , Type>& );
int msg_id { MsgId };
};
template< int MsgId , typename T>
QDataStream& operator <<( QDataStream& out , const msg< MsgId , T >& m )
{
return out << m.msg_id << m.data;
}
template< int MsgId, typename T>
QDataStream& operator >>( QDataStream& in , msg< MsgId , T >& m )
{
return in >> m.msg_id >> m.data;
}
struct server_status
{
int number_of_active_users {};
int station_load {};
};
QDataStream& operator <<( QDataStream& out , const server_status& s )
{
return out << s.station_load << s.number_of_active_users;
}
QDataStream& operator >>( QDataStream& in , server_status& s )
{
return in >> s.station_load >> s.number_of_active_users;
}
struct error_occurred
{
int code;
QString msg;
};
QDataStream& operator <<( QDataStream& out , const error_occurred& e )
{
return out << e.code << e.msg;
}
QDataStream& operator >>( QDataStream& in , error_occurred& e )
{
return in >> e.code >> e.msg;
}
int main( int argc , char** argv)
{
QCoreApplication a { argc , argv };
// Serialize to byte array
QByteArray msg_buffer;
QDataStream out { &msg_buffer , QIODevice::WriteOnly };
msg<10 , server_status> m;
m.data.station_load = 54;
m.data.number_of_active_users = 112;
out << m;
msg<11 , error_occurred> e;
e.data.msg = "Device temperature is so high.";
e.data.code = 401;
out << e;
// Send over udp
// some_udp_socket->write( msg_buffer );
auto incomed_datagram = msg_buffer; // some_udp_socket->receiveDatagram().data();
QDataStream in { &incomed_datagram , QIODevice::ReadOnly };
while( !in.atEnd() )
{
int msg_id {};
in >> msg_id;
if ( msg_id == 10 )
{
server_status s;
in >> s;
qDebug() << "station_load : %" << s.station_load << "active_users :" << s.number_of_active_users;
}
else if ( msg_id == 11 )
{
error_occurred e;
in >> e;
qDebug() << "code :" << e.code << "msg :" << e.msg;
}
}
a.exec();
}
message_id正在检查并手动初始化相应的类,但可以编写一个模板类,该模板类根据message_id自动调度和初始化消息。
相关文章:
- 将结构字段的类型展开为可变模板参数
- 如何通过UDP接收QByteArray并将其解析为位字段结构?
- 结构字段名称与 GDB 中的 STL 数组冲突
- 如何使用位字段将数据从二进制文件复制到结构中?
- 结构体和类的不同大小(),彼此具有相同的字段类型
- 如何避免在数据结构中包含存储为字段的类?
- 带有 char[] 字段的 POD 结构的 constexpr 构造
- 初始化派生结构的基部分/意外打包派生结构字段以对齐基结构的间隙
- 结构数组中所有类似字段的总和
- 如何为结构字段动态分配字符空间
- 使用 Boost::Hana 中的 BOOST_HANA_DEFINE_STRUCT 定义具有 40 个以上字段的结构
- 实例化时结构字段中的默认值
- sizeof 函数如何在带和不带位字段的结构上工作?(填充)
- 如何使用函数的输出初始化 const 数组结构字段?
- 如何通知侦听器结构的哪个字段已更新
- 无法访问 Arduino 结构字段。错误"退出状态 1。xxxx 不命名类型"
- 列出常量和数组结构字段的初始化
- 指向结构中的数组的指针,其中每个字段都是一个动态数组
- MEMCMP以相同(零值)位字段结构返回非零
- 位字段结构分配意外行为