Qt 利用TCP/IP socket通信 发送与接收结构体(简单通信协议解析)

📅 发布时间:2026/7/12 22:22:42 👁️ 浏览次数:
Qt 利用TCP/IP socket通信 发送与接收结构体(简单通信协议解析)
Qt 利用TCP/IP socket通信 发送与接收结构体简单通信协议解析Chapter1 Qt 利用TCP/IP socket通信 发送与接收结构体简单通信协议解析Chapter2 自定义协议方案一、总体架构设计1.1 数据结构定义二、核心实现方案2.1 混合序列化类2.2 TCP通信管理器2.3 服务器端实现三、数据格式示例3.1 JSON消息示例四、优化和错误处理Chapter1 Qt 利用TCP/IP socket通信 发送与接收结构体简单通信协议解析原文链接简述在Qt里利用TCP/IP协议socket套接字设计实现结构体的收发类似实现简单的自定义通信协议。描述发送的结构体包含帧头header占两字节、数据长度dataLength占一字节、数据my_data不多于64字节、校验和check_sum前面所有数据所占字节和本身只占一个字节。发送方的结构体这里要特别注意 #pragma pack(1) 的使用涉及到结构体内存对齐使用这行可以设置结构体对齐方式为1字节这点特别重要我在这个坑里绕了好久才走出来这样设置主要是因为后面要使用到结构体的大小sizeof(senddata)。Chapter2 自定义协议方案我们设计一个混合方案使用QDataStream序列化结构体数据然后将得到的QByteArray转换为Base64编码的字符串放入JSON中。这样我们可以利用JSON的可读性和扩展性同时保证结构体中浮点数等二进制数据的精度。步骤定义结构体并使用QDataStream进行序列化和反序列化。将序列化后的QByteArray转换为Base64字符串以便放入JSON。构建JSON对象包含必要的字段其中结构体数据部分为Base64字符串。通过TCP传输JSON字符串。接收方解析JSON字符串提取Base64字符串解码为QByteArray然后反序列化为结构体。注意由于JSON是文本格式不能直接嵌入二进制数据所以需要Base64编码。以下为详细代码示例首先定义结构体以SensorData为例和其序列化/反序列化方法QT TCP传输JSON格式数据方案含结构体二进制数据一、总体架构设计1.1 数据结构定义// 原始结构体定义#pragmapack(push,1)structSensorData{qint64 timestamp;// 时间戳毫秒floattemperature;// 温度floathumidity;// 湿度doublepressure;// 气压quint8 sensor_id;// 传感器ID};#pragmapack(pop)// JSON消息结构structJsonMessage{QString message_type;// 消息类型data/command/responseQString device_id;// 设备标识quint32 sequence;// 序列号QByteArray binary_data;// 结构体二进制数据QString checksum;// 校验和qint64 send_time;// 发送时间戳};二、核心实现方案2.1 混合序列化类classHybridSerializer{public:// 结构体转QDataStream二进制数据staticQByteArraystructToBinary(constSensorDatadata){QByteArray byteArray;QDataStreamstream(byteArray,QIODevice::WriteOnly);// 设置高精度模式stream.setVersion(QDataStream::Qt_5_15);stream.setFloatingPointPrecision(QDataStream::DoublePrecision);// 写入结构体数据streamdata.timestampdata.temperaturedata.humiditydata.pressuredata.sensor_id;returnbyteArray;}// 二进制数据转结构体staticSensorDatabinaryToStruct(constQByteArraybinaryData){SensorData data;QDataStreamstream(binaryData);stream.setVersion(QDataStream::Qt_5_15);stream.setFloatingPointPrecision(QDataStream::DoublePrecision);streamdata.timestampdata.temperaturedata.humiditydata.pressuredata.sensor_id;returndata;}// 生成JSON消息包含二进制数据staticQByteArraycreateJsonMessage(constJsonMessagemsg){QJsonObject jsonObj;// 添加文本字段jsonObj[message_type]msg.message_type;jsonObj[device_id]msg.device_id;jsonObj[sequence]static_castqint64(msg.sequence);jsonObj[checksum]msg.checksum;jsonObj[send_time]msg.send_time;// 二进制数据转为Base64编码if(!msg.binary_data.isEmpty()){QString base64DataQString::fromLatin1(msg.binary_data.toBase64());jsonObj[binary_data]base64Data;jsonObj[data_size]msg.binary_data.size();jsonObj[data_format]qdatastream_binary;}// 添加版本信息jsonObj[protocol_version]1.0;jsonObj[encoding]utf-8;QJsonDocumentdoc(jsonObj);returndoc.toJson(QJsonDocument::Compact);}// 解析JSON消息staticJsonMessageparseJsonMessage(constQByteArrayjsonData){JsonMessage msg;QJsonParseError parseError;QJsonDocument docQJsonDocument::fromJson(jsonData,parseError);if(parseError.error!QJsonParseError::NoError){msg.message_typeerror;returnmsg;}QJsonObject jsonObjdoc.object();// 解析文本字段msg.message_typejsonObj[message_type].toString();msg.device_idjsonObj[device_id].toString();msg.sequencestatic_castquint32(jsonObj[sequence].toInt());msg.checksumjsonObj[checksum].toString();msg.send_timestatic_castqint64(jsonObj[send_time].toDouble());// 解析二进制数据Base64解码if(jsonObj.contains(binary_data)){QString base64StrjsonObj[binary_data].toString();msg.binary_dataQByteArray::fromBase64(base64Str.toLatin1());}returnmsg;}// 生成校验和CRC32staticQStringcalculateChecksum(constQByteArraydata){quint32 crc0xFFFFFFFF;for(inti0;idata.size();i){crc^static_castquint8(data.at(i));for(intj0;j8;j){crc(crc1)^((crc1)?0xEDB88320:0);}}crc^0xFFFFFFFF;returnQString(%1).arg(crc,8,16,QChar(0)).toUpper();}};2.2 TCP通信管理器classTcpJsonClient:publicQObject{Q_OBJECTpublic:explicitTcpJsonClient(QObject*parentnullptr):QObject(parent){socketnewQTcpSocket(this);connect(socket,QTcpSocket::connected,this,TcpJsonClient::onConnected);connect(socket,QTcpSocket::readyRead,this,TcpJsonClient::onReadyRead);connect(socket,QTcpSocket::disconnected,this,TcpJsonClient::onDisconnected);connect(socket,QOverloadQAbstractSocket::SocketError::of(QAbstractSocket::error),this,TcpJsonClient::onError);}// 发送结构体数据voidsendSensorData(constSensorDatasensorData){// 1. 结构体转二进制QByteArray binaryDataHybridSerializer::structToBinary(sensorData);// 2. 创建JSON消息JsonMessage jsonMsg;jsonMsg.message_typesensor_data;jsonMsg.device_idsensor_001;jsonMsg.sequencecurrentSequence;jsonMsg.binary_databinaryData;jsonMsg.send_timeQDateTime::currentMSecsSinceEpoch();// 3. 计算校验和对二进制数据jsonMsg.checksumHybridSerializer::calculateChecksum(binaryData);// 4. 生成JSON字符串QByteArray jsonDataHybridSerializer::createJsonMessage(jsonMsg);// 5. 添加帧头长度信息QByteArray frame;QDataStreamframeStream(frame,QIODevice::WriteOnly);frameStream.setVersion(QDataStream::Qt_5_15);frameStreamstatic_castquint32(jsonData.size());frame.append(jsonData);// 6. 发送数据if(socket-state()QAbstractSocket::ConnectedState){socket-write(frame);socket-flush();emitdataSent(jsonMsg.sequence,jsonData.size());}}// 接收数据处理voidonReadyRead(){buffer.append(socket-readAll());while(buffer.size()4){// 至少有长度信息// 读取消息长度quint32 messageLength;QDataStreamlengthStream(buffer);lengthStream.setVersion(QDataStream::Qt_5_15);lengthStreammessageLength;if(buffer.size()messageLength4){return;// 数据不完整等待}// 提取JSON数据QByteArray jsonDatabuffer.mid(4,messageLength);buffer.remove(0,messageLength4);// 解析JSON消息JsonMessage jsonMsgHybridSerializer::parseJsonMessage(jsonData);if(jsonMsg.message_typeerror){emitparseError(JSON解析错误);continue;}// 验证校验和QString calculatedChecksumHybridSerializer::calculateChecksum(jsonMsg.binary_data);if(calculatedChecksum!jsonMsg.checksum){emitchecksumError(jsonMsg.sequence);continue;}// 处理不同类型的消息processMessage(jsonMsg);}}private:voidprocessMessage(constJsonMessagemsg){if(msg.message_typesensor_data){// 二进制数据转结构体SensorData sensorDataHybridSerializer::binaryToStruct(msg.binary_data);// 发送信号处理数据emitsensorDataReceived(sensorData,msg.device_id,msg.send_time);// 可选发送确认响应sendAckResponse(msg.sequence);}elseif(msg.message_typeack){emitacknowledgmentReceived(msg.sequence);}}voidsendAckResponse(quint32 sequence){JsonMessage ackMsg;ackMsg.message_typeack;ackMsg.device_idclient_001;ackMsg.sequencesequence;ackMsg.send_timeQDateTime::currentMSecsSinceEpoch();QByteArray jsonDataHybridSerializer::createJsonMessage(ackMsg);// 添加长度头QByteArray frame;QDataStreamframeStream(frame,QIODevice::WriteOnly);frameStreamstatic_castquint32(jsonData.size());frame.append(jsonData);socket-write(frame);}signals:voiddataSent(quint32 sequence,qint64 size);voidsensorDataReceived(constSensorDatadata,constQStringdeviceId,qint64 timestamp);voidacknowledgmentReceived(quint32 sequence);voidparseError(constQStringerror);voidchecksumError(quint32 sequence);private:QTcpSocket*socket;QByteArray buffer;quint32 currentSequence0;};2.3 服务器端实现classTcpJsonServer:publicQTcpServer{Q_OBJECTprotected:voidincomingConnection(qintptr socketDescriptor)override{ClientThread*threadnewClientThread(socketDescriptor,this);connect(thread,ClientThread::sensorDataReceived,this,TcpJsonServer::processSensorData);connect(thread,ClientThread::finished,thread,QObject::deleteLater);thread-start();}privateslots:voidprocessSensorData(constSensorDatadata,constQStringclientId){// 处理接收到的数据qDebug()Received data fromclientIdTemperature:data.temperatureHumidity:data.humidityPressure:data.pressure;}};// 客户端线程处理classClientThread:publicQThread{Q_OBJECTpublic:ClientThread(qintptr socketDescriptor,QObject*parentnullptr):QThread(parent),socketDescriptor(socketDescriptor){}voidrun()override{QTcpSocket socket;if(!socket.setSocketDescriptor(socketDescriptor)){emiterror(socket.error());return;}QByteArray buffer;while(socket.state()QAbstractSocket::ConnectedState){if(socket.waitForReadyRead(1000)){buffer.append(socket.readAll());// 消息处理逻辑与客户端类似while(buffer.size()4){quint32 messageLength;QDataStreamlengthStream(buffer);lengthStreammessageLength;if(buffer.size()messageLength4){break;}QByteArray jsonDatabuffer.mid(4,messageLength);buffer.remove(0,messageLength4);JsonMessage jsonMsgHybridSerializer::parseJsonMessage(jsonData);if(jsonMsg.message_typesensor_data){SensorData sensorDataHybridSerializer::binaryToStruct(jsonMsg.binary_data);emitsensorDataReceived(sensorData,jsonMsg.device_id);}}}}socket.disconnectFromHost();socket.waitForDisconnected();}signals:voidsensorDataReceived(constSensorDatadata,constQStringclientId);voiderror(QAbstractSocket::SocketError socketError);private:qintptr socketDescriptor;};三、数据格式示例3.1 JSON消息示例{message_type:sensor_data,device_id:sensor_001,sequence:12345,checksum:A1B2C3D4,send_time:1677654321000,binary_data:AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fnAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrqwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5jp6uvs7e7v8PHy8/T19vf4fr7/P3/w,data_size:29,data_format:qdatastream_binary,protocol_version:1.0,encoding:utf-8}四、优化和错误处理待进一步完善。