您的位置:首页 > 理论基础 > 计算机网络

QTcpSocket 通讯 ( 服务器、客户端、封包、解包 )

2017-10-08 15:48 411 查看

转载请注明出处:http://blog.csdn.net/lthcth111/article/details/78175341

一、简介

简单实现 QTcpSocket  通讯,包含有服务器、客户端界面,和封包、解包过程,示例界面如下。



二、数据包结构



注:长度 = sizeof( 包类型
a5ca
+ 数据 + 包尾 )

三、部分代码展示

封包

// 封包并发送
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: