写了一个小的Qt网络程序,很简单,发送的网络消息除了字符串还有一个结构体。很简单的想到用memcpy()函数来将数据序列化为BYTE数组从而实现网络传输。

序列化是Java中一个概念,C中并没有,C++中后来引入了序列化和反序列化的概念。序列化是指将非系统类型的类的对象通过序列化操作转换成基本数据格式,从而达到便于网络传输或者文件读写的目的。反序列化是序列化的逆操作。

注:C/C++中BYTE与Char在内存中数据一样,形式相同,在Windef.h中有一行:

  typedef unsigned char BYTE;

故而,在内存中char和BYTE是一样的,序列化的目标为BYTE和char是等效的。

而QUdpSocket需要的是char型的网络传输格式,序列化的结果就是BYTE或者char型。

而序列化为char型,就不得不提C/C++中的内存对准问题,个人的经验是尽量多用char、BYTE等定长类型,少用int,double等变长类型,来进行序列化,因为在不同系统中,变长类型会因为系统的不同而定义为不同长度的内存位,进而系统会特定性的进行内存对齐,导致序列化后的反序列化出现乱码。

实在需要使用类似的结构或者类型,则尽量将其岔开,并且通过不同长度类型隔开来保证内存始终对齐至理想位置。并且,相对的,尽量将“较大”的类型变量靠前放置。

-------------------------------------------------------------------------------------------------------

现在描述遇到的问题:

  需求:通过Qt界面得到操作信息,并保存到一个结构体中,初始化一个UDPSocket对象,将结构体序列化为char型后,通过网络发送。

  实现:Qt界面通过QImage类的对象,得到图像信息并获取操作数据。自定义结构体如下:

 typedef struct tagDrawInfo
{
TOOLS m_Tool; /// 绘图工具;TOOLS为自定义enum联合体。
int width; /// 画笔宽度;
QColor lineColor; /// 线条颜色;
QColor fillColor; /// 填充颜色;
Qt::BrushStyle
brushStyle; /// 画刷风格;
QPoint startPoint; /// 开始点;
QPoint endPoint;  /// 结束点;
}DRAWINFO;

  通过memcpy()函数来实现内存拷贝,达到序列化的目的。

  问题:接收端得到的DRAWINFO对象,值为意料之外值,进而程序不能通过当前对象完成进一步操作。

  解决:1)自己定义序列化函数,将特定对象放置于指定位置,保证反序列化时数据位置和预期一样。分别对结构体的每部分序列化和反序列化,利用各类型的构造函数初始化对象,完成反序列化。

     2)对DRAWINFO定义顺序进行调整,对变长类型对象进行分离,确保系统内存的自动对齐不会对数据位置产生影响。更改过后的结构体定义如下:

 typedef struct tagDrawInfo
{
  Qt::BrushStyle
brushStyle; /// 画刷风格;
QPoint endPoint;  /// 结束点;
QColor fillColor; /// 填充颜色;
QColor lineColor; /// 线条颜色;
TOOLS m_Tool; /// 绘图工具;TOOLS为自定义enum联合体。
QPoint startPoint; /// 开始点;
int width; /// 画笔宽度;
}DRAWINFO;

  结果:对定义顺序进行调整后,接收端的DRAWINFO对象反序列化功能正常。

  分析:C++编译器,会对int型、bool型等边长类型进行内存对齐,提高内存利用效率,进而提高CPU一个工作周期内可处理指令条数,提高程序运行效率,但是在自动完成一些功能时会产生意外的问题,需要适当调整。

  而关于内存对准的问题,今天欠下一笔,日后有时间进行详解~

Qt中QUdpSocket序列化问题的更多相关文章

  1. QT中的线程与事件循环理解(1)

    1.需要使用多线程管理的例子 一个进程可以有一个或更多线程同时运行.线程可以看做是“轻量级进程”,进程完全由操作系统管理,线程即可以由操作系统管理,也可以由应用程序管理.Qt 使用QThread 来管 ...

  2. Qt 框架的图形性能高(OpenGL上的系统效率高),网络性能低,开发效率高,Quick是可以走硬件加速——Qt中分为好几套图形系统,差不多代表了2D描画的发展史。最经典的软描画系统

    -----图形性能部分-----Qt的widgets部分,运行时的图像渲染性能是一般的,因为大部分的界面内容都是Qt自绘,没有走硬件加速,也就是说很多图形内容都是CPU算出来的.但是widgets底层 ...

  3. 关于QT中的音频通信问题

    今天给大家讲说一个新的东西,使用QT实现音频通信的功能,挺起来是不是很高大上啊,哈哈,实际上我们只是使用一些接口做一些简单的工作而已,并不是让你写一个传输协议和采集音频信息,好了,那我们就来说一说关于 ...

  4. 4.关于QT中的QFile文件操作,QBuffer,Label上添加QPixmap,QByteArray和QString之间的区别,QTextStream和QDataStream的区别,QT内存映射(

     新建项目13IO 13IO.pro HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += gui widgets network CON ...

  5. QT中使用MinGW 编译的protobuf库--包含库的生成和使用

    QT中使用MinGW 编译的protobuf库--包含库的生成和使用 0前言 1准备工作 2生成protobuf库文件 3在QT中测试protobuf的使用 4结语 0前言 最近要在QT中使用prot ...

  6. Qt中使用Json

    Qt中使用Json需要一下几个类: QJsonValue            代表了json格式中的一个值 QJsonObject          代表了json格式的一个对象 QJsonArra ...

  7. 4.关于QT中的QFile文件操作,QBuffer,Label上加入QPixmap,QByteArray和QString之间的差别,QTextStream和QDataStream的差别,QT内存映射(

     新建项目13IO 13IO.pro HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += gui widgets network CON ...

  8. Qt 中使用Singleton模式需小心

    在qt中,使用Singleton模式时一定要小心.因为Singleton模式中使用的是静态对象,静态对象是直到程序结束才被释放的,然而,一旦把该静态对象纳入了Qt的父子对象体系,就会导致不明确的行为. ...

  9. qt中ui的 使用介绍

    1.什么是ui?ui通常是用Qt 设计师设计出来的界面文件的后缀.通常情况下ui是一个指向这个界面类的指针.ui-> 一般就是用来访问这个界面类里面的控件.例如你的ui文件里有一个叫okButt ...

随机推荐

  1. Greedy:Allowance(POJ 3040)

    零用钱大作战 题目大意:农夫和牛又搞新花样了,现在农夫想给Bessie每个星期都给一点零用钱,农夫有一堆面值的钱币,并且这个钱币都能被上一个钱币整除(1,5,10,50),并且钱币有一定数量,要你求最 ...

  2. php截取指定字符串之间的字符串的类

    一个php截取指定字符串之间的字符串的类 <?php   class get_c_str {   var $str;   var $start_str;   var $end_str;   va ...

  3. java写入文件的几种方法分享

    转自:http://www.jb51.net/article/47062.htm 一,FileWritter写入文件 FileWritter, 字符流写入字符到文件.默认情况下,它会使用新的内容取代所 ...

  4. activity切换时的overridePendingTransition动画效 (转)

    注意,切换方法overridePendingTransition只能在startActivity和finish方法之后调用.第一个参数为第一个Activity离开时的动画,第二参数为所进入的Activ ...

  5. jq生成目录文件树jQuery Ztree基本用法

    转自:http://www.cnblogs.com/linjiqin/p/4547452.html 1.首先在页面上有<ul/>标签 ? 1 <ul id="tree&qu ...

  6. 使用VIRTUALBOX安装ANDROID系统 | 图文教程 | 相关设置

    使用VIRTUALBOX安装ANDROID系统 | 图文教程 | 相关设置 http://icaoye.com/virtualbox-run-android/

  7. 使用redis-cli定时执行指定命令

    50 20 * * * echo "del counterv2_real" | redis-cli -h hosts -a id:pwd --pipe

  8. Hark的数据结构与算法练习之梳排序

    算法说明梳排序是交换排序的一种,它其实也是改自冒泡排序,不同之处是冒泡排序的比较步长恒定为1,而梳排序的比较步长是变化的. 步长需要循环以数组长度除以1.3,到最后大于等于1即可. 光说可能比较抽象, ...

  9. SU supef命令学习

  10. 递推DP URAL 1260 Nudnik Photographer

    题目传送门 /* 递推DP: dp[i] 表示放i的方案数,最后累加前n-2的数字的方案数 */ #include <cstdio> #include <algorithm> ...