QTcpSocket在收到disconnect数据丢失的问题
来源:互联网 发布:淘宝女装宣传语 编辑:程序博客网 时间:2024/06/06 00:32
最近在使用Qt做一个GUI,用于结合MySQL进行pdf类型的生产工艺文件的存储,将路径和文件名放到Mysql中,将文件存在文件系统中,
本来想使用ftp来做的,后来想了想,麻烦,就自己做了一个C/S来实现。
主要实现3种操作就可以:
enum{
ZPacket_Upload_File=0x1101,// 上传文件
ZPacket_Download_File=0x1102,// 下载文件
ZPacket_Delete_File=0x1103,// 删除文件
};
其它的复制,移动等暂时不考虑。
QTcpSocket在使用异步接收数据时,在收到对方发来的disconnect时,缓冲区的数据有可有还没有全部读取出来,就会造成错误。
这里提供一个方法可以将其全部读出来处理。
一切尽在代码中,看吧,亲们。
#include "zfilethread.h"
#include <QDir>
#include <QtEndian>
ZFileThread::ZFileThread(QObject *parent) :
QThread(parent)
{
this->moveToThread(this);
this->m_nPacketLength=0;
this->m_nReceivedLength=0;
}
ZFileThread::~ZFileThread()
{
delete this->m_tcpSocket;
}
void ZFileThread::ZFunctionSetSocketFd(qint32 sockFd)
{
this->m_sockFd=sockFd;
}
void ZFileThread::run()
{
this->m_tcpSocket=new QTcpSocket;
this->m_tcpSocket->setSocketDescriptor(this->m_sockFd);
connect(this->m_tcpSocket,SIGNAL(readyRead()),this,SLOT(ZSlotReadDataFromSocket()));
connect(this->m_tcpSocket,SIGNAL(disconnected()),this,SLOT(ZSlotConnectionDisconnect()));
connect(this->m_tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(ZSlotSocketError(QAbstractSocket::SocketError)));
this->exec();
}
void ZFileThread::ZSlotReadDataFromSocket()
{
//receive packet length first.
if(this->m_nPacketLength<=0)
{
if(this->m_tcpSocket->bytesAvailable()>=sizeof(qint32))
{
quint8 tBuffer[4];
this->m_tcpSocket->read((char*)tBuffer,sizeof(qint32));
this->m_nPacketLength=qFromBigEndian<quint32>(tBuffer);
qDebug()<<"length:"<<this->m_nPacketLength;
}
}else{
//we need receive more data.
if(this->m_nReceivedLength<this->m_nPacketLength)
{
qint64 tCanReadBytes=this->m_tcpSocket->bytesAvailable();
qDebug()<<"can read:"<<tCanReadBytes;
if(tCanReadBytes>this->m_nPacketLength-this->m_nReceivedLength);
{
tCanReadBytes=this->m_nPacketLength-this->m_nReceivedLength;
}
QByteArray tReceivedBytes=this->m_tcpSocket->read(tCanReadBytes);
qDebug()<<"ReceivedBytes:"<<tReceivedBytes.size();
if(tReceivedBytes.size()>0)
{
this->m_RecvBuffer.append(tReceivedBytes);
this->m_nReceivedLength+=tReceivedBytes.size();
qDebug()<<"TotalLength:"<<this->m_nReceivedLength;
}
}
//received finish ?
if(this->m_nReceivedLength>=this->m_nPacketLength)
{
this->ZFunctionParsePacket();
//release memory after using.
this->m_RecvBuffer.clear();
this->m_nPacketLength=0;
this->m_nReceivedLength=0;
}
}
}
void ZFileThread::ZSlotSocketError(QAbstractSocket::SocketError sockError)
{
switch(sockError)
{
case QAbstractSocket::RemoteHostClosedError:
qDebug()<<"client closed socket";
break;
default:
break;
}
}
void ZFileThread::ZFunctionParsePacket()
{
qDebug()<<"parse packet:";
//parse packet.
qint32 tOffset=0;
uchar tBuffer[4];
//packet type.
memcpy(tBuffer,this->m_RecvBuffer.data()+tOffset,sizeof(qint32));
qint32 tPacketType=qFromBigEndian<qint32>(tBuffer);
tOffset+=sizeof(qint32);
qDebug("Packet Type:0x%x",tPacketType);
//file name length.
memcpy(tBuffer,this->m_RecvBuffer.data()+tOffset,sizeof(qint32));
qint32 tFileNameLen=qFromBigEndian<qint32>(tBuffer);
tOffset+=sizeof(qint32);
//file name.
QString tFileName=QString().fromLatin1(this->m_RecvBuffer.data()+tOffset,tFileNameLen);
tOffset+=tFileNameLen;
qDebug()<<"FileNameLen:"<<tFileNameLen<<",FileName:"<<tFileName;
//parse packet according to different types.
switch(tPacketType)
{
case ZPacket_Upload_File:
{
//file data length.
qint32 tFileDataLen=qFromBigEndian<qint32>((uchar*)(this->m_RecvBuffer.data()+tOffset));
tOffset+=sizeof(qint32);
qDebug("Packet Type:0x%x",tPacketType);
qDebug()<<"File name len:"<<tFileNameLen<<",FileName:"<<tFileName;
qDebug()<<"File data len:"<<tFileDataLen;
//find directory name.
if(!tFileName.endsWith(QString(".pdf")))
{
qDebug()<<"invalid file format!";
return;
}
//create directory.
//the file name element's format is
// type1/a.pdf
qint32 tDirEndIndex=tFileName.lastIndexOf('/');
qDebug()<<tDirEndIndex;
QString tDirPath=tFileName.mid(0,tDirEndIndex);
tDirPath.prepend(QDir::currentPath()+"/uploads/");
qDebug()<<"path:"<<tDirPath;
QDir tDir(tDirPath);
if(!tDir.exists())
{
if(false==tDir.mkpath(tDirPath))
{
qDebug()<<"create path failed!";
return;
}
}
//create file,and write data.
QString tOnlyFileName=tFileName.mid(tDirEndIndex+1,-1);
qDebug()<<"OnlyFileName:"<<tOnlyFileName;
QFile tFile(tOnlyFileName.prepend(tDirPath+"/"));
if(!tFile.open(QIODevice::WriteOnly))
{
qDebug()<<"open file failed!";
return;
}
tFile.write(this->m_RecvBuffer.data()+tOffset+0,tFileDataLen);
tFile.close();
qDebug()<<"upload file ok";
}
break;
case ZPacket_Download_File:
break;
case ZPacket_Delete_File:
break;
default:
break;
}
return;
}
void ZFileThread::ZSlotConnectionDisconnect()
{
qDebug()<<"disconnect!";
while(this->m_tcpSocket->bytesAvailable()>0)
{
qDebug()<<"Still Have Data:"<<this->m_tcpSocket->bytesAvailable();
//read again.
this->ZSlotReadDataFromSocket();
}
this->exit(0);
emit this->ZSignalCanCloseMe(this);
}
#include "zfileserver.h"
#include <zfilethread.h>
#include <QDebug>
ZFileServer::ZFileServer(QObject *parent) :
QTcpServer(parent)
{
}
void ZFileServer::incomingConnection(qint32 sockFd)
{
qDebug()<<"New Connection:"<<sockFd;
ZFileThread *tThread=new ZFileThread;
tThread->ZFunctionSetSocketFd(sockFd);
connect(tThread,SIGNAL(ZSignalCanCloseMe(ZFileThread*)),this,SLOT(ZSlotDeleteThread(ZFileThread*)));
this->m_ThreadList.append(tThread);
tThread->start();
}
void ZFileServer::ZSlotDeleteThread(ZFileThread *thread)
{
for(qint32 i=0;i<this->m_ThreadList.count();i++)
{
ZFileThread *tThread=this->m_ThreadList.at(i);
if(tThread==thread)
{
tThread->wait();
delete tThread;
this->m_ThreadList.removeAt(i);
qDebug()<<"delete thread ok!";
}
}
}
看,俺传输一个4M左右的文件,简直是秒传呀。
- QTcpSocket在收到disconnect数据丢失的问题
- QTcpSocket 遇到的问题!
- QT QTcpSocket发送数据问题
- 项目总结-HttpURLConnection的disconnect的问题
- QTcpSocket 发送数据的几种方法
- QTcpSocket 发送数据的几种方法
- mina2 收到重复数据问题
- 解决服务器收到的post数据出现部分乱码问题
- 数据丢失精确度的问题的解决
- 串口通信数据丢失的问题
- hibernate莫名其妙的数据丢失问题
- svn管理数据丢失问题的解决办法
- postgres unlogged表的数据丢失问题
- SharedPreferences 存储集合数据丢失的问题
- redis数据丢失问题的分析
- ORACLE在使用distinct可能因为查询的列过少导致数据丢失的问题
- QTcpSocket的连续发送数据和连续接收数据
- QTcpSocket的连续发送数据和连续接收数据
- 使用任意波形(或函数)发生器产生想要的任意信号
- Eclipse加入外部Tomcat服务器之后修改无效
- JavaScript表单验证-不弹出窗口直接提示错误信息
- ActiveMQ, RabbitMQ,ZeroMQ比较与评测
- Liferay中actionURL能够执行后台方法 ,但是页面不跳转问题解决方案
- QTcpSocket在收到disconnect数据丢失的问题
- CSAPP 关于数据对齐
- 从Stellaris®外设驱动库学到的东西之一---变量的命名
- 一段代码弄清楚CSS属性display和visibility的差别,以及dom元素可见的条件
- jsp出现getOutputStream() has already been called for this response异常的原因和解决方法
- ASP.NET实现进度条
- cas server端的login-webflow详细流程
- excel画图
- Failed to load Main-Class manifest attribute from ....