QT实现FTP服务器(三)
QFtpClient类的实现:
#include "QFtpClient.h" #include <QDebug> #include <QThread> #include <QDebug> #include <QHostAddress> #include <QFileInfo> #include <QDir> #include <QFileInfoList> #include <QStringList> #include <QDateTime> #include <QElapsedTimer> #include <QCoreApplication> #include "QClientThread.h" #include <QHostInfo> #define PACKET_SIZE 4096 const char *Month[12] = //文件日期填充需要用到的月份表示 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; /*********************************************************************************************** *函数名 : QFtpClient *函数功能描述 : FTP客户端构造函数 *函数参数 : socketDescriptor 控制socket的描述符 parent 富对象 *函数返回值 : *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ QFtpClient::QFtpClient(qintptr socketDescriptor,QObject *parent) : QObject(parent) { m_socketDescriptor = socketDescriptor; m_Server = NULL; m_pDataSocket = NULL; m_strRemoteHost = ""; m_strRemotePort = -1; m_dwRestartOffset = 0; m_bPassiveMode = false; m_bdataSocketConnected = false; m_nStatus = STATUS_IDLE; m_strLocalIPv4 = ""; } /*********************************************************************************************** *函数名 : InitilizeAfterConstructed *函数功能描述 : FTP客户端构造以后的初始化工作 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::InitilizeAfterConstructed() { m_pCtrlSocket = new QTcpSocket; m_pCtrlSocket->setSocketDescriptor(m_socketDescriptor); m_pCtrlSocket->moveToThread(m_pThreadIn); connect(m_pCtrlSocket,SIGNAL(readyRead()),this,SLOT(slotReadCtrlSocket())); connect(m_pCtrlSocket,SIGNAL(disconnected()),this,SLOT(slotCtrlSocketDisConnected())); connect(m_pThreadIn,SIGNAL(finished()),this,SLOT(slotThreadFinished())); SendResponse("220 Welcome Using Nelson FTPS"); m_strCtrlSocketBuff.clear(); } /*********************************************************************************************** *函数名 : slotThreadFinished *函数功能描述 :线程结束后发出finished信号的槽函数 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::slotThreadFinished() { if(m_pCtrlSocket) { delete m_pCtrlSocket; m_pCtrlSocket = NULL; } } /*********************************************************************************************** *函数名 : slotCtrlSocketDisConnected *函数功能描述 : 控制socket断开连接 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/4 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::slotCtrlSocketDisConnected() { if(m_upLoadFile.isOpen()) m_upLoadFile.close(); //关闭文件 m_pCtrlSocket->close(); DestroyDataConnection(); if(m_pThreadIn->isRunning()) { QClientThread* p = (QClientThread* )m_pThreadIn; p->ClientExit(); m_pThreadIn->quit(); } } /*********************************************************************************************** *函数名 : slotReadCtrlSocket *函数功能描述 : 读控制socket的槽函数 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::slotReadCtrlSocket() { while(m_pCtrlSocket->bytesAvailable()) { int length = m_pCtrlSocket->bytesAvailable(); QByteArray readBufArr = m_pCtrlSocket->read(length); QString msg = readBufArr; int nIndex = msg.indexOf("\r\n"); if(nIndex == -1) { return ; } msg = msg.left(nIndex); m_CtrlSocketCmdsList.append(msg); while(m_CtrlSocketCmdsList.size() > 0) { ProcessCommand(); } } } /*********************************************************************************************** *函数名 : GetCommandLine *函数功能描述 : 从控制socket读缓存中获取命令参数 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::GetCommandLine() { QString strtmp; int nIndex; while(!m_strCtrlSocketBuff.isEmpty()) { nIndex = m_strCtrlSocketBuff.indexOf("\r\n"); if(nIndex != -1) { strtmp = m_strCtrlSocketBuff.left(nIndex); m_strCtrlSocketBuff = m_strCtrlSocketBuff.mid(nIndex+2); if(!strtmp.isEmpty()) { m_CtrlSocketCmdsList.append(strtmp); ProcessCommand(); } } else break; } } /*********************************************************************************************** *函数名 : ProcessCommand *函数功能描述 : 处理FTP客户端发来的命令 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::ProcessCommand(void) { QString strCommand,strArgs; QString strBuf = m_CtrlSocketCmdsList.takeFirst(); int nIndex = strBuf.indexOf(" "); //找空格 if(nIndex == -1) { strCommand = strBuf; } else { strCommand = strBuf.left(nIndex); strArgs = strBuf.mid(nIndex+1); } strCommand.toUpper(); //qDebug()<<strCommand<<" "<<strArgs; //<<" ThreadID:"<<QThread::currentThreadId(); if(strCommand == "USER") { if(strArgs == "mm") { SendResponse("331 User name ok,need password."); m_UserName = strArgs; } else { SendResponse("530 Not logged in. No such accout."); } } else if(strCommand == "PASS") { if(m_UserName.isEmpty()) { SendResponse("503 Login with USER first."); return ; } if(strArgs == "mm") { m_UserPassword = strArgs; m_nUserStatus = STATUS_IDLE; SendResponse("230 User Login Success."); m_strHomeDir = "E:/FTPDIR"; //设置主目录 m_strCurrentDir = m_strHomeDir; //设置当前目录 } } else if(strCommand == "TYPE") { SendResponse("200 Type set to %s",strArgs.toLatin1().data()); } else if(strCommand == "QUIT") { SendResponse("220 GoodBye."); if(m_upLoadFile.isOpen()) m_upLoadFile.close(); //关闭文件 m_pCtrlSocket->close(); DestroyDataConnection(); if(m_pThreadIn->isRunning()) { QClientThread* p = (QClientThread* )m_pThreadIn; p->ClientExit(); m_pThreadIn->quit(); } } else if(strCommand == "PWD" || strCommand == "XPWD") { QString strRelativePath; GetRelativePath(m_strCurrentDir, strRelativePath); SendResponse("257 \"%s\" is current directory.",strRelativePath.toLatin1().data()); } else if(strCommand == "CWD") { DoChangeDirectory(strArgs); } else if(strCommand == "PORT") { if(!ExtractRemoteHost(strArgs)) { return ; } SendResponse("200 Port command successful."); } else if(strCommand == "PASV") { DestroyDataConnection(); newDataServer(); } else if(strCommand == "SIZE") { QString strLocalPath; GetLocalPath(strArgs,strLocalPath); QFileInfo fi(strLocalPath); if(fi.isFile() && fi.exists()) { SendResponse("213 %d",fi.size()); } else { SendResponse("550 File not found."); } } else if(strCommand == "RETR") //download { DoRetrieveFile(strArgs); } else if((strCommand == "LIST")||(strCommand == "NLIST")) //list files { QString strResult; if(!GetDirectoryList(strArgs,strResult)) { return ; } SendResponse("150 Opening ASCII mode data connection for directory list."); QByteArray cstr = strResult.toUtf8(); qint64 actWritten; actWritten = m_pDataSocket->write(cstr); if(actWritten != cstr.size()) { SendResponse("426 connection closed:transfer aborted."); } m_pDataSocket->waitForBytesWritten(); m_pDataSocket->close(); DestroyDataConnection(); SendResponse("226 Transfer complete"); } else if(strCommand == "STOR") //upload { SendResponse("150 Opening BINARY mode data connection for file transfer."); m_nStatus = STATUS_UPLOAD; m_strUpLoading = m_strCurrentDir +"/" + strArgs; m_upLoadFile.setFileName(m_strUpLoading); m_upLoadFile.open(QIODevice::WriteOnly); if(m_pDataSocket == NULL) m_pDataSocket = new QTcpSocket; connect(m_pDataSocket,SIGNAL(readyRead()),this,SLOT(slotReadDataSocket())); connect(m_pDataSocket,SIGNAL(disconnected()),this,SLOT(dataSocketDisconnected())); m_pDataSocket->connectToHost(m_strRemoteHost,m_strRemotePort); } else if(strCommand == "DELE") //delete files { DoDeleteFile(strArgs); } else if((strCommand == "RMD")||(strCommand == "XRMD")) //remove directory { DoDeleteDirectory(strArgs); } else if(strCommand == "RNFR") { DoRenameFrom(strArgs); } else if(strCommand == "RNTO") { DoRenameTo(strArgs); } } /*********************************************************************************************** *函数名 : newDataServer *函数功能描述 : 新建数据socket服务器,然后等待客户端连接上来 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/7 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::newDataServer() { QString localHostName = QHostInfo::localHostName(); QHostInfo hostInfo = QHostInfo::fromName(localHostName); //获取主机信息 for (int i = 0;i < hostInfo.addresses().size();i++) { if(hostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { if(hostInfo.addresses()[i].toString().startsWith("192.168.1.")) { m_strLocalIPv4 = hostInfo.addresses()[i].toString(); } } } QHostAddress m_HostInfo; m_HostInfo.setAddress(m_strLocalIPv4); m_Server=new QTcpServer(this); m_Server->listen(m_HostInfo,0); connect(m_Server,SIGNAL(newConnection()),this,SLOT(slotNewDataSocketConnected())); quint16 uPort = m_Server->serverPort(); //套接字端口号 QString strIP = m_HostInfo.toString(); //套接字IP strIP.replace(QString("."),QString(",")); SendResponse("227 Entering Passive Mode (%s,%d,%d).",strIP.toLatin1().data(),uPort/256,uPort%256); m_bPassiveMode = true; QElapsedTimer t; t.start(); while(t.elapsed()<5000) //在此等待5S 等客户连接上来 { if(m_bdataSocketConnected == true) { m_bdataSocketConnected = false; break; } QCoreApplication::processEvents(); } } /*********************************************************************************************** *函数名 : DoRenameTo *函数功能描述 : 处理重命名的RETO命令 *函数参数 : strname 要重命名的文件名或者文件夹名 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/7 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::DoRenameTo(QString strname) { QString fileName; fileName = m_strCurrentDir + "/" + strname; fileName.replace(QString("//"),QString("/")); if(m_strRenameFile.isEmpty()) { SendResponse("503 Bad sequence of commands."); return ; } QString strRelativePath; //要求回复用相对路径 GetRelativePath(m_strRenameFile,strRelativePath); if(m_bRenameFile) { QFile file(fileName); //要被重命名的名字 if(file.exists()) { SendResponse("550 File already exists."); return ; } file.setFileName(m_strRenameFile); //原文件 if(file.rename(fileName)) { SendResponse("250 File \"%s\" renamed successfully.",strRelativePath.toLatin1().data()); } else { SendResponse("450 Internal error renaming the file: \"%s\".",strRelativePath.toLatin1().data()); } } else { QDir dir(fileName); if(dir.exists()) //文件夹存在 { SendResponse("550 Directory already exists."); return ; } dir.setCurrent(m_strRenameFile); //当前目录 if(dir.rename(m_strRenameFile,fileName)) { SendResponse("250 File \"%s\" renamed successfully.",strRelativePath.toLatin1().data()); } else { SendResponse("450 Internal error renaming the file: \"%s\".",strRelativePath.toLatin1().data()); } } m_strRenameFile.clear(); } /*********************************************************************************************** *函数名 : DoRenameFrom *函数功能描述 :处理重命名的REFR命令 *函数参数 : 被重命名的文件名或者文件夹名 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/7 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::DoRenameFrom(QString strname) { QString fileName; fileName = m_strCurrentDir + "/" + strname; fileName.replace(QString("//"),QString("/")); m_bRenameFile = false; QFile file(fileName); if(file.exists()) { m_bRenameFile = true; m_strRenameFile = fileName; SendResponse("350 File exists,ready for destination name."); return ; } else { QDir dir(fileName); if(dir.exists()) { m_bRenameFile = false; m_strRenameFile = fileName; SendResponse("350 File exists,ready for destination name."); return ; } else { SendResponse("550 File/Directory not found."); m_bRenameFile = false; m_strRenameFile.clear(); return ; } } } /*********************************************************************************************** *函数名 : DoDeleteDirectory *函数功能描述 : 删除服务器上的文件夹 *函数参数 : strdir 被删除的文件夹名 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/7 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::DoDeleteDirectory(QString strdir) { QString strLocalPath; GetLocalPath(strdir,strLocalPath); QDir dir(strLocalPath); if(!dir.exists()) { SendResponse("550 Directory not found."); return ; } if(!dir.removeRecursively()) { SendResponse("450 Internal error deleting the directory: \"%s\".",strdir.toLatin1().data()); return; } else { SendResponse("250 Directory \"%s\" was deleted successfully.",strdir.toLatin1().data()); } } /*********************************************************************************************** *函数名 : DoDeleteFile *函数功能描述 : 删除服务器上的文件 *函数参数 : strfile 被删除的文件名 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/7 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::DoDeleteFile(QString strfile) { QString filePath; filePath = m_strCurrentDir + "/" + strfile; filePath.replace(QString("//"),QString("/")); QFile file(filePath); if(!file.exists()) { SendResponse("550 File not found."); return ; } if(file.remove()) { SendResponse("250 File \"%s\" was deleted successful.",strfile.toLatin1().data()); } else { SendResponse("450 Internal error deleting the file: \"%s\".",strfile.toLatin1().data()); } } /*********************************************************************************************** *函数名 : ExtractRemoteHost *函数功能描述 : 提取客户端发来的PORT命令携带的对方IP和端口信息 *函数参数 : strArgs PORT命令附带的参数 *函数返回值 : 成功返回true,失败返回false *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ bool QFtpClient::ExtractRemoteHost(QString strArgs) { int port=0; QString strIP=""; int nCount = strArgs.count(QChar(','), Qt::CaseSensitive); if(nCount != 5) { return false; } strArgs += ","; //为了方便提取参数,增加一个',' nCount = 0; while(1) { int index = strArgs.indexOf(","); //例:"192,168,1,9,84,65" if(index == -1) { break; } nCount++; switch(nCount) { case 1: //"192" strIP += strArgs.left(index)+"."; strArgs = strArgs.right(strArgs.length()-index-1); break; case 2: //"168" strIP += strArgs.left(index)+"."; strArgs = strArgs.right(strArgs.length()-index-1); break; case 3: //"1" strIP += strArgs.left(index)+"."; strArgs = strArgs.right(strArgs.length()-index-1); break; case 4: strIP += strArgs.left(index); strArgs = strArgs.right(strArgs.length()-index-1); break; case 5: port = strArgs.left(index).toInt()*256; strArgs = strArgs.right(strArgs.length()-index-1); break; case 6: port += strArgs.left(index).toInt(); strArgs.clear(); break; } } m_strRemotePort = port; m_strRemoteHost = strIP; return true; } /*********************************************************************************************** *函数名 : GetDirectoryList *函数功能描述 : 获取当前文件夹下的文件信息 *函数参数 : strArgs 当前文件夹目录 strResult 文件信息结果存储 *函数返回值 : 成功返回true 失败返回false *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ bool QFtpClient::GetDirectoryList(QString strArgs,QString &strResult) { QString strDirectory = strArgs; strDirectory = ""; QDir dir(m_strCurrentDir); if(!dir.exists()) return false; QStringList strFileList; QFileInfoList list=dir.entryInfoList(strFileList,QDir::AllEntries,QDir::DirsFirst); for(int i=0;i<list.count();i++) { QFileInfo tempFileInfo = list.at(i); if(tempFileInfo.isDir()) { strResult += "drwx------"; } else { strResult += "-rwx------"; } strResult += " 1 user group "; // groups QString strLength = QString("%1").arg(tempFileInfo.size()); //file size QString strFiller = " "; strResult += strFiller.left(strFiller.size()-strLength.size()); strResult += strLength; QString fileTime; QDateTime fileCreateDat = tempFileInfo.created(); //文件创建日期 QDateTime nowTime =QDateTime::currentDateTime(); //当前日期 qint64 dis = nowTime.daysTo(fileCreateDat); if((dis > 350)||(tempFileInfo.lastModified()>nowTime)) { QString strMonth = QString(" %1").arg( Month[fileCreateDat.date().month() - 1]); QString strDay = QString(" %1").arg(fileCreateDat.date().day()); QString strYear = QString(" %1 ").arg(fileCreateDat.date().year()); fileTime += strMonth + strDay + strYear; //月日年格式 } else { QString strMonth = QString(" %1").arg(Month[fileCreateDat.date().month() - 1]); QString strDay = QString(" %1").arg(fileCreateDat.date().day()); QString time = QString(" %1:%2 ").arg(fileCreateDat.time().hour()).arg(fileCreateDat.time().second()); fileTime += strMonth + strDay + time; } strResult += fileTime; //文件时间 strResult+=tempFileInfo.fileName(); //加上文件名 strResult+="\r\n"; } return true; } /*********************************************************************************************** *函数名 : StripParamters *函数功能描述 : *函数参数 : *函数返回值 : *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::StripParamters(QString args) { QString strBuff = ""; bool bIsParam = false; for(int i=0;i<args.length();i++) { if(args.at(i) == QChar('-')) { bIsParam = true; } if(args.at(i) == QChar(' ') && bIsParam) { bIsParam = false; continue ; } if(!bIsParam) { strBuff += args.at(i); } } args = strBuff; } /*********************************************************************************************** *函数名 : DoRetrieveFile *函数功能描述 : 下载文件 *函数参数 : filename 下载文件的文件名 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::DoRetrieveFile(QString filename) { QString strLocalPath; GetLocalPath(filename,strLocalPath); QFileInfo fi(strLocalPath); if(fi.isFile() && fi.exists()) { SendResponse("150 Opening BINARY mode data connection for file transfer"); } else { SendResponse("550 File not found."); return ; } SendFile(strLocalPath); //本地地址名 } /*********************************************************************************************** *函数名 : SendFile *函数功能描述 : 发送文件 *函数参数 : *函数返回值 : *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::SendFile(QString lpszFileName) { if(!PreSendFile(lpszFileName)) { SendResponse("426 Connection closed: transfer aborted."); return ; } QFile file(lpszFileName); if(!file.open(QIODevice::ReadOnly)) { return ; } m_nTotalBytesTransfered = 0; //先设定死 while(m_nTotalBytesTransfered < m_nTotalBytesSend) { qint64 actWritten; QByteArray readByte = file.read(PACKET_SIZE); m_nTotalBytesTransfered += readByte.size(); actWritten = m_pDataSocket->write(readByte); if(actWritten != readByte.size()) { SendResponse("426 connection closed:transfer aborted."); } } m_pDataSocket->close(); //关闭数据连接端口 SendResponse("226 Transfer complete"); } /*********************************************************************************************** *函数名 : PreSendFile *函数功能描述 : 发送文件前检查文件是否存在 *函数参数 : lpszFileName 要发送的文件名 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ bool QFtpClient::PreSendFile(QString lpszFileName) { QFile file(lpszFileName); if(file.open(QIODevice::ReadOnly)) { m_nTotalBytesSend = file.size(); if(m_dwRestartOffset < m_nTotalBytesSend) { m_nTotalBytesTransfered = m_dwRestartOffset; } else { m_nTotalBytesTransfered = 0; } file.close(); return true; } else { return false; } } /*********************************************************************************************** *函数名 : slotNewDataSocketConnected *函数功能描述 : tcp数据服务监听端口 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::slotNewDataSocketConnected() { m_pDataSocket = m_Server->nextPendingConnection(); m_Server->close(); connect(m_pDataSocket,SIGNAL(readyRead()),this,SLOT(slotReadDataSocket())); m_bdataSocketConnected = true; } /*********************************************************************************************** *函数名 : slotReadDataSocket *函数功能描述 : 读数据套接字 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::slotReadDataSocket() { while(m_pDataSocket->bytesAvailable()) { QByteArray dataArray; int length = m_pDataSocket->bytesAvailable(); dataArray = m_pDataSocket->read(length); if(m_nStatus == STATUS_UPLOAD) { qint64 n = m_upLoadFile.write(dataArray); if(n != dataArray.size()) { qDebug()<<"write file data error!"; } } } } /*********************************************************************************************** *函数名 : dataSocketDisconnected *函数功能描述 : 数据套接字被断开的槽函数 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::dataSocketDisconnected() { m_pDataSocket->close(); //数据套接字关闭 SendResponse("226 Transfer complete"); } /*********************************************************************************************** *函数名 : DestroyDataConnection *函数功能描述 : 销毁数据连接 *函数参数 : 无 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::DestroyDataConnection() { if(m_pDataSocket != NULL) { delete m_pDataSocket; m_pDataSocket = NULL; } if(m_Server != NULL) { if(m_Server->isListening()) m_Server->close(); delete m_Server; m_Server = NULL; } m_strRemoteHost = ""; m_strRemotePort = -1; m_dwRestartOffset = 0; m_bPassiveMode = false; m_pDataSocket = NULL; } /*********************************************************************************************** *函数名 : DoChangeDirectory *函数功能描述 : 更改当前的工作目录 *函数参数 : strPath *函数返回值 : *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::DoChangeDirectory(QString strPath) { if(strPath.endsWith("..")) { strPath = strPath.left(strPath.length() - 2); //remove .. m_strCurrentDir = m_strCurrentDir + strPath; m_strCurrentDir = m_strCurrentDir.replace("//","/"); QDir dir(m_strCurrentDir); if(!dir.cdUp()) { SendResponse("550 Directory not found."); return ; } m_strCurrentDir = dir.path(); } else { m_strCurrentDir = m_strCurrentDir + strPath; m_strCurrentDir = m_strCurrentDir.replace("//","/"); QDir dir(m_strCurrentDir); if(!dir.exists()) { SendResponse("550 Directory not found."); return ; } m_strCurrentDir = dir.path(); } QString strRelativePath; GetRelativePath(m_strCurrentDir,strRelativePath); SendResponse("250 Directory changed to \"%s\".",strRelativePath.toLatin1().data()); } /*********************************************************************************************** *函数名 : GetRelativePath *函数功能描述 : 从绝对路径转相对路径,从当前路径得到相对于主目录的路径 *函数参数 : lpszLocalPath 绝对路径 strRelativePath 相对路径 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::GetRelativePath(QString lpszLocalPath, QString &strRelativePath) { QString strOffset = m_strHomeDir; //这是主目录 "E:/FTPDIR" QString strLocalPath = lpszLocalPath; //传进来的参数是当前 if (strOffset.right(1) != QString("/")) //最后有没有反斜杠 strOffset += "/"; //没有就加上 if (strLocalPath.right(1) != QString("/")) //当前路径 strLocalPath += "/"; if (strOffset == strLocalPath) //如果当前路径就是主目录 { strRelativePath = "/"; //那么相对路径就设置为"/" } else { //例如当前路径是"E:temp\ADir\",而主目录是“E:temp”,那么相对路径就是\ADir strRelativePath = strLocalPath; //相对路径就是当前路径,然后将主目录的部分用“/”代替 strRelativePath.replace(strOffset, "/"); } } /*********************************************************************************************** *函数名 : GetLocalPath *函数功能描述 : 从相对路径获得绝对路径 *函数参数 : lpszRelativePath 相对路径 strLocalPath 绝对路径 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ void QFtpClient::GetLocalPath(QString lpszRelativePath, QString &strLocalPath) { QString strRelativePath = lpszRelativePath; //相对路径 if(strRelativePath.left(1) == "/") { strLocalPath = m_strHomeDir+strRelativePath; } else { strLocalPath = m_strCurrentDir+"/"+strRelativePath; } strLocalPath.replace(QString("//"), QString("/")); } /*********************************************************************************************** *函数名 : SendResponse *函数功能描述 : 给客户段的回复 *函数参数 : pcFormat 回复字符串 *函数返回值 : 无 *作者 : nelson *函数创作日期 : 2016/3/3 *函数修改日期 : *修改人 : *修改原因 : *版本 : 1.0 *历史版本 : 无 ***********************************************************************************************/ bool QFtpClient::SendResponse(const char *pcFormat, ...) { QString input; char buf[100]={0}; va_list pArg; va_start(pArg,pcFormat); vsprintf(buf,pcFormat,pArg); input = buf; input += "\r\n"; if(m_pCtrlSocket->state() == QAbstractSocket::ConnectedState) { m_pCtrlSocket->write(input.toStdString().c_str(), strlen(input.toStdString().c_str())); m_pCtrlSocket->waitForBytesWritten(); } return 0; }