在使用QT网络通信时一直是简单的发送数据--接收数据,常见的就是发送一个字符串/字节流,然后根据这个字符串/字节流提取出有用的信息。 这样在不是很复杂的通信中可以满足实际需要。但也有弊端,就是每次写网络通信时都是口头约定一个协议,让发送方与接收方都满足这个协议才可以进行正常通信。 这样如果我每次写这样的程序,我都要首先规定好一个的通讯协议,然后再编写相应的代码。
那么如何传输更复杂的数据呢,而且可以不用上述的口头协议?
在JAVA,C#中都有对对象序列化的概念,QT里也有,利用将对象序列化传输可以对更加方便地传输我们构造的一些复杂对象数据。
QT序列化
The QDataStream allows you to serialize some of the Qt data types. The table below lists the data types that QDataStream can serialize and how they are represented. The format described below is version 12. It is always best to cast integers to a Qt integer type, such as qint16 or quint32, when reading and writing. This ensures that you always know exactly what size integers you are reading and writing, no matter what the underlying platform and architecture the application happens to be running on.
序列化就是将一个类变成一系列的字节,利用反序列化也可以将这些字节构造出原始的这个类。这些字节可以直接存储在硬盘上,当然也可以通过网络发送出去。利用以上这些特点我们就可以开始进行一些有意思的网络通信。
当然也不是所有的类都能满足可序列化,QT 对满足序列化的类进行了说明
bool boolean qint8 signed byte qint16 signed 16-bit integer qint32 signed 32-bit integer qint64 signed 64-bit integer quint8 unsigned byte quint16 unsigned 16-bit integer quint32 unsigned 32-bit integer quint64 unsigned 64-bit integer float 32-bit floating point number using the standard IEEE 754 format double 64-bit floating point number using the standard IEEE 754 format const char * The string length (quint32) The string bytes, excluding the terminating 0 QBitArray The array size (quint32) The array bits, i.e. (size + 7)/8 bytes QBrush The brush style (quint8) The brush color (QColor) If style is CustomPattern, the brush pixmap (QPixmap) QByteArray If the byte array is null: 0xFFFFFFFF (quint32) Otherwise: the array size (quint32) followed by the array bytes, i.e. size bytes QColor Color spec (qint8) Alpha value (quint16) Red value (quint16) Green value (quint16) Blue value (quint16) Pad value (quint16) QCursor Shape ID (qint16) If shape is BitmapCursor: The bitmap (QPixmap), mask (QPixmap), and hot spot (QPoint) QDate Julian day (quint32) QDateTime Date (QDate) Time (QTime) 0 for Qt::LocalTime, 1 for Qt::UTC (quint8) QEasingCurve type (quint8) func (quint64) hasConfig (bool) If hasConfig is true then these fields follow: list period (double) amplitude (double) overshoot (double) QFont The family (QString) The point size (qint16) The style hint (quint8) The char set (quint8) The weight (quint8) The font bits (quint8) QHash<Key, T> The number of items (quint32) For all items, the key (Key) and value (T) QIcon The number of pixmap entries (quint32) For all pixmap entries: The pixmap (QPixmap) The file name (QString) The pixmap size (QSize) The mode (quint32) The state (quint32) QImage If the image is null a "null image" marker is saved; otherwise the image is saved in PNG or BMP format (depending on the stream version). If you want control of the format, stream the image into a QBuffer (using QImageIO) and stream that. QKeySequence A QList<int>, where each integer is a key in the key sequence QLinkedList<T> The number of items (quint32) The items (T) QList<T> The number of items (quint32) The items (T) QMap<Key, T> The number of items (quint32) For all items, the key (Key) and value (T) QMatrix(obsolete) m11 (double) m12 (double) m21 (double) m22 (double) dx (double) dy (double) QMatrix4x4 m11 (double) m12 (double) m13 (double) m14 (double) m21 (double) m22 (double) m23 (double) m24 (double) m31 (double) m32 (double) m33 (double) m34 (double) m41 (double) m42 (double) m43 (double) m44 (double) QPair<T1, T2> first (T1) second (T2) QPalette The disabled, active, and inactive color groups, each of which consists of the following: foreground (QBrush) button (QBrush) light (QBrush) midlight (QBrush) dark (QBrush) mid (QBrush) text (QBrush) brightText (QBrush) buttonText (QBrush) base (QBrush) background (QBrush) shadow (QBrush) highlight (QBrush) highlightedText (QBrush) link (QBrush) linkVisited (QBrush) QPen The pen styles (quint8) The pen width (quint16) The pen color (QColor) QPicture The size of the picture data (quint32) The raw bytes of picture data (char) QPixmap Save it as a PNG image. QPoint The x coordinate (qint32) The y coordinate (qint32) QQuaternion The scalar component (double) The x coordinate (double) The y coordinate (double) The z coordinate (double) QRect left (qint32) top (qint32) right (qint32) bottom (qint32) QRegExp The regexp pattern (QString) Case sensitivity (quint8) Regular expression syntax (quint8) Minimal matching (quint8) QRegion The size of the data, i.e. 8 + 16 * (number of rectangles) (quint32) 10 (qint32) The number of rectangles (quint32) The rectangles in sequential order (QRect) QSize width (qint32) height (qint32) QString If the string is null: 0xFFFFFFFF (quint32) Otherwise: The string length in bytes (quint32) followed by the data in UTF-16 QTime Milliseconds since midnight (quint32) QTransform m11 (double) m12 (double) m13 (double) m21 (double) m22 (double) m23 (double) m31 (double) m32 (double) m33 (double) QUrl Holds an URL (QString) QVariant The type of the data (quint32) The null flag (qint8) The data of the specified type QVector2D the x coordinate (double) the y coordinate (double) QVector3D the x coordinate (double) the y coordinate (double) the z coordinate (double) QVector4D the x coordinate (double) the y coordinate (double) the z coordinate (double) the w coordinate (double) QVector<T> The number of items (quint32) The items (T)
上面这些已经足够强大了,试想一下,你在本地构造一个QList/QImage,能够完整地传输到对方,而且不用编写相关的构造代码就可以将对象传输过去能够省去多少力气。
今天写了一个DEMO演示了一下,感觉效果还不错。
首先构造一个自己的可序列化的类
class DataPackage { public: QString label_1; QString label_2; friend QDataStream& operator >>(QDataStream& so,DataPackage& de); friend QDataStream& operator <<(QDataStream& de,DataPackage& so); };
然后重载操作符
QDataStream& operator>> (QDataStream& so,DataPackage& de) { return so>>de.label_1>>de.label_2; } QDataStream& operator<< (QDataStream& de,DataPackage& so) { return de<<so.label_1<<so.label_2; }
这样发送方发送的时候
void MainWindow::send_button() { if(!this->socketA){ this->ui->statusBar->showMessage("not a socket",5000); return; } DataPackage package; package.label_1=this->ui->A1->text(); package.label_2=this->ui->A2->text(); QByteArray by; QDataStream ds(&by,QIODevice::WriteOnly); ds<<package; this->socketA->write(by); }
接收方接收的时候
void MainWindow::socketB_recv() { QByteArray by= this->socketB->readAll(); QDataStream ds(&by,QIODevice::ReadOnly); DataPackage package; ds>>package; this->ui->B1->setText(package.label_1); this->ui->B2->setText(package.label_2); }
以上轻松传递一个对象,重载的操作符<<相当与序列化这个对象。>>相当与反序列化对象。这样如果双方写协议的时候只需要构造一个协议包,然后两边分别进行序列化反序列化操作进行通信了,配合QT默认的类型将通信内容更加复杂化,使用更加便捷化。