南通精诚建设集团有限公司网站,目前做网站框架,python 网站开发神器,网站seo推广方案当时用TCP协议传输数据时#xff0c;经常出现粘包的现象 当服务器向客户端发送数据之后#xff0c;客户端还没有接收数据的时候#xff0c;这段时间数据在什么地方#xff1f; 1、服务器#xff1f;服务器已经发出数据了 2、网线#xff1f;数据应该在内存#xff0c;怎…当时用TCP协议传输数据时经常出现粘包的现象 当服务器向客户端发送数据之后客户端还没有接收数据的时候这段时间数据在什么地方 1、服务器服务器已经发出数据了 2、网线数据应该在内存怎么会在网线里面又没有内存 3、客户端是的这个时候数据已经到达客户端了只不过被保存在客户端的缓存中了内核缓冲区客户端只有在read的时候才能读出数据 场景服务器每次给客户端发出一条数据但是每次发送数据的量是不一样的这时要求客户端把服务器发过来的数据依次接收到本地并且进行对应的解析如果客户端一次发出10个字节那么客户端也一次读出10个字节如果多读了那么就把下一条数据读出来了此时解析数据会是错误的这就是TCP粘包
处理办法发送端在每一个数据包前面加上包头包头中加入数据长度 接收端接收到后的处理首先包头的大小是固定的一般就是一个long或者int类型所以我们根据这个long或者int类型求出一个固定大小8字节long或者4字节int所以在读数据包的时候直接根据这个类型先去读8字节或者4字节这样就可以读出数据包的长度然后根据这个长度去读后边的这个数据块 比如此次接收到的长度为100那么就向后读取100个字节的数据就是此次的一个包哪怕此时缓冲区有1000个字节数据只读这100个字节就能获取一个完整的包剩余的900个字节就需要下一次去处理下次处理的时候还是先读包头读出数据包的一个长度然后根据这个长度去读取相应的数据这样一次一次读取就可以一点一点把数据拆分出来了
例这里以Qt编写的基于opencv的人脸识别的服务器和客户端为例客户端发送拍下的人脸发送到服务器进行识别要求传输一帧完整的人脸数据这就有可能粘包可能同时发送两个人脸向服务器此时就需要处理粘包 首先客户端发送图片数据
//把Mat数据转化为QbyteArray --》编码成jpg格式
std::vectoruchar buf;
cv::imencode(.jpg,srcImage,buf); //这就是将拍摄的原始的图像转为jpg然后将数据放到buf中
QByteArray byte((const char*)buf.data(),buf.size()); //数据格式转为QByteArray
//准备发送
quint64 backsize byte.size(); //获取数据的长度这里可以看到backsize是quint64型变量占8个字节
QByteArray sendData;
QDataStream stream(sendData,QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_14);
//将数据放入码流首先放入数据的长度backsizequint64为8字节的长度后面就是数据
streambacksizebyte;
//发送
msocket.write(sendData); //将数据包发送服务器接收图片数据
static quint64 bsize 0; //全局变量QDataStream stream(msocket); //把套接字绑定到数据流
stream.setVersion(QDataStream::Qt_5_14);if(bsize 0){//查看目前TCP的内存缓冲区的数据长度是否能达到bsize所占的字节数这里应该是8字节if( msocket-bytesAvailable() (qint64)sizeof(bsize) ) return ;//说明数据长度够8个字节然后就可以获取采集数据的长度streambsize;
}//获取目前缓存中剩余数据的长度小于刚才获取的8字节的数据长度说明数据还没有发送完成返回继续等待
if(msocket-bytesAvailable() bsize)
{return ; //此时bsize没有清空下次还会来这里检查获取的数据长度是否大于或等于bsize
}
QByteArray data;
streamdata;
bsize 0; // 将bsize设为0说明处理完了一包数据
if(data.size() 0)//没有读取到数据
{return;
}//显示图片
QPixmap mmp;
mmp.loadFromData(data,jpg);
mmp mmp.scaled(ui-picLb-size());
ui-picLb-setPixmap(mmp);