转载请注明出处:http://blog.youkuaiyun.com/lthcth111/article/details/78175341
一、简介
简单实现 QTcpSocket 通讯,包含有服务器、客户端界面,和封包、解包过程,示例界面如下。![]()
二、数据包结构
注:长度 = sizeof( 包类型 + 数据 + 包尾 )
三、部分代码展示
- 封包
// 封包并发送 void SocketClient::send(QByteArray data, QByteArray dataType) { QTcpSocket *socket = m_dataSocket; if(socket == NULL || (socket != NULL && socket->state() != QTcpSocket::ConnectedState)) { return; } QByteArray packet = dataType + data + NET_PACKET_END; //[包类型 + 数据 + 包尾] //长度占8字节,前面补零,如"00065536" int size = packet.size(); QByteArray length = QByteArray().setNum(size); length = QByteArray(NET_PACKET_LTNGTH_BYTES, '0') + length; length = length.right(NET_PACKET_LTNGTH_BYTES); packet.insert(0, NET_PACKET_START + length);//插入 [包头 + 数据长度] socket->write(packet); }
- 解包
// 读取 socket 数据 void SocketClient::OnReadyRead() { QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender()); if(socket == m_dataSocket ) { m_dataPacket.data += socket->readAll(); // 循环解析包数据,m_dataPacket.data 中可能不只一包数据 bool isOk = false; do{ isOk = parsePacket(socket, &m_dataPacket); }while(isOk); } else { MY_LOG("socket connection abnormal"); } } // 解包 bool SocketClient::parsePacket(QTcpSocket *socket, SocketPacket *packet) { int pIndexStart = packet->data.indexOf(NET_PACKET_START); if(pIndexStart < 0) { return false; } packet->data = packet->data.mid(pIndexStart); //截取从包头index_start到末尾的数据 SocketPacket tmpPacket; tmpPacket.data = packet->data; tmpPacket.data.remove(0, QByteArray(NET_PACKET_START).size());//删除包头 //解析包长度 if(tmpPacket.data.count() < NET_PACKET_LTNGTH_BYTES) { return false; } bool isOk; tmpPacket.length = tmpPacket.data.mid(0, NET_PACKET_LTNGTH_BYTES).toLong(&isOk); if(isOk == false) { packet->data.remove(0, QByteArray(NET_PACKET_START).size());//删除包头 if(packet->data.indexOf(NET_PACKET_START) >= 0) { return true;//有可能出现粘包的情况,继续解析后面数据 } else { return false; } } //数据到达包长度 tmpPacket.data.remove(0, NET_PACKET_LTNGTH_BYTES);//删除数据长度 if(tmpPacket.length > tmpPacket.data.count()) { return false; } //包尾是否匹配 tmpPacket.data.resize(tmpPacket.length);//删除多余数据 if(tmpPacket.data.endsWith(NET_PACKET_END) == false) { packet->data.remove(0, QByteArray(NET_PACKET_START).size());//删除包头 if(packet->data.indexOf(NET_PACKET_START) >= 0) { return true;//有可能出现粘包的情况,继续解析后面数据 } else { return false; } } tmpPacket.data.resize(tmpPacket.length - QByteArray(NET_PACKET_END).count()); //删除包尾 //解析出数据类型 if(tmpPacket.data.count() < NET_PACKET_TYPE_BYTES) { return false; } QByteArray dataType = tmpPacket.data.left(NET_PACKET_TYPE_BYTES); tmpPacket.dataType = dataType; tmpPacket.data.remove(0, NET_PACKET_TYPE_BYTES);//删除数据类型 //发送数据包消息 if(socket == m_dataSocket) { emit dataPacketReady(tmpPacket); } //删除当前包数据 packet->data.remove(0, QByteArray(NET_PACKET_START).size() + NET_PACKET_LTNGTH_BYTES + tmpPacket.length); return true; }
四、完整代码下载
优快云 下载
客户端和服务器: http://download.youkuaiyun.com/download/lthcth111/10011256
码云下载
服务器: https://gitee.com/2649549484/TcpServerSimple
五、开发环境
Win7 + Qt 5.5.0