QTcpSocket 通讯 ( 服务器、客户端、封包、解包 )
2017年10月08日 15:48:11 lthcth111 阅读数 1403更多
分类专栏: Qt
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lthcth111/article/details/78175341
转载请注明出处:http://blog.csdn.net/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;
}
四、完整代码下载
CSDN 下载客户端和服务器: http://download.csdn.net/download/lthcth111/10011256
码云下载客户端:https://gitee.com/2649549484/TcpClientSimple
服务器: https://gitee.com/2649549484/TcpServerSimple
五、开发环境
Win7 + Qt 5.5.0