本文共 5581 字,大约阅读时间需要 18 分钟。
最近在使用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左右的文件,简直是秒传呀。