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[] = //文件日期填充需要用到的月份表示
{
"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 = -;
m_dwRestartOffset = ;
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 == -)
{
return ;
}
msg = msg.left(nIndex); m_CtrlSocketCmdsList.append(msg);
while(m_CtrlSocketCmdsList.size() > )
{
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 != -)
{
strtmp = m_strCtrlSocketBuff.left(nIndex);
m_strCtrlSocketBuff = m_strCtrlSocketBuff.mid(nIndex+);
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 == -)
{
strCommand = strBuf;
}
else
{
strCommand = strBuf.left(nIndex);
strArgs = strBuf.mid(nIndex+);
}
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 = ;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,);
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/,uPort%);
m_bPassiveMode = true;
QElapsedTimer t;
t.start();
while(t.elapsed()<) //在此等待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=;
QString strIP="";
int nCount = strArgs.count(QChar(','), Qt::CaseSensitive);
if(nCount != )
{
return false;
} strArgs += ","; //为了方便提取参数,增加一个','
nCount = ;
while()
{
int index = strArgs.indexOf(","); //例:"192,168,1,9,84,65"
if(index == -)
{
break;
}
nCount++;
switch(nCount)
{
case : //"192"
strIP += strArgs.left(index)+".";
strArgs = strArgs.right(strArgs.length()-index-);
break;
case : //"168"
strIP += strArgs.left(index)+".";
strArgs = strArgs.right(strArgs.length()-index-);
break;
case : //"1"
strIP += strArgs.left(index)+".";
strArgs = strArgs.right(strArgs.length()-index-);
break;
case :
strIP += strArgs.left(index);
strArgs = strArgs.right(strArgs.length()-index-);
break;
case :
port = strArgs.left(index).toInt()*;
strArgs = strArgs.right(strArgs.length()-index-);
break;
case :
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=;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 > )||(tempFileInfo.lastModified()>nowTime))
{
QString strMonth = QString(" %1").arg( Month[fileCreateDat.date().month() - ]);
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() - ]);
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=;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 = ; //先设定死 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 = ;
} 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 = -;
m_dwRestartOffset = ;
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() - ); //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() != QString("/")) //最后有没有反斜杠
strOffset += "/"; //没有就加上 if (strLocalPath.right() != 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() == "/")
{
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[]={};
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 ;
}

QT实现FTP服务器(三)的更多相关文章

  1. ftp服务器三种模式

    一.匿名开放模式(最不安全) 1.[root@localhost ~]# vim  /etc/vsftpd/vsftpd.conf  (主配置) anonymous_enable=YES    //允 ...

  2. QT实现FTP服务器(二)

    QClientThread类的实现: #include "QClientThread.h" #include <QDebug> /******************* ...

  3. QT实现FTP服务器(一)

    QListenSocket类的实现: #include "QListenSocket.h" #include <QTcpSocket> #include <QDe ...

  4. 【大话QT之十】实现FTP断点续传(需要设置ftp服务器为“PASV”被动接收方式)

    应用需求: 网盘开发工作逐步进入各部分的整合阶段,当用户在客户端修改或新增加一个文件时,该文件要同步上传到服务器端对应的用户目录下,因此针对数据传输(即:上传.下载)这一块现在既定了三种传输方式,即: ...

  5. CentOS6.5下搭建ftp服务器(三种认证模式:匿名用户、本地用户、虚拟用户)

    CentOS 6.5下搭建ftp服务器 vsftpd(very secure ftp daemon,非常安全的FTP守护进程)是一款运行在Linux操作系统上的FTP服务程序,不仅完全开源而且免费,此 ...

  6. Python09作业思路及源码:高级FTP服务器开发(仅供参考)

    高级FTP服务器开发 一,作业要求 高级FTP服务器开发 用户加密认证(完成) 多用户同时登陆(完成) 每个用户有不同家目录且只能访问自己的家目录(完成) 对用户进行磁盘配额,不同用户配额可不同(完成 ...

  7. 超简单——自己搭建ftp服务器

    自己搭建ftp服务器 之所以没选择serv-u,一是因为收费,虽说网上有破解版,但是使用过程中发现破解版很不稳定,经常异常死掉,随后改选用免费的filezilla. 1软件获取 从百度搜索 FileZ ...

  8. 文件服务器:FTP服务器详解

    文件服务器:FTP服务器 数据传输原理 功能简介 文件的传输与管理 不同等级的用户身份:user.guest.anonymous 实体用户.权限较完整 匿名用户.下载资源的能力 命令记录与日志文件记录 ...

  9. Linux 搭建FTP服务器

    介绍 本章主要介绍在Linux中搭建FTP服务器的过程,需要掌握的要点是配置文件的合理配置. 知识点 在linux中使用的FTP是vsftp FTP可以有三种登入方式分别是: 匿名登录方式:不需要用户 ...

随机推荐

  1. mysql5.7.23版本环境配置

    亲身实践安装mysql,用时居然花费了三个小时,在有那么多教程的情况下,依然在不该花费时间的路上浪费了太多时间.希望这篇文章能够帮助大家少走弯路~~ 1.下载我下载的是64位. 2.解压下载之后,我选 ...

  2. BZOJ 4822 [Cqoi2017]老C的任务 ——树状数组

    直接离散化之后用树状数组扫一遍. 把每一个询问拆成四个就可以做了. %Silvernebula 怒写KD-Tree #include <map> #include <cmath> ...

  3. BZOJ2726 [SDOI2012]任务安排 【斜率优化 + cdq分治】

    题目 机器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3...N.这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i ...

  4. Hibernate get 和 load区别

    Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象.下边详细说一下get和load的不同,因为有些时候为了对比也会把find加进来. 1.从返回 ...

  5. localStorage增删改查

    /** * 设置 本地缓存 */ export function setStorage(key, obj) { if (typeof obj === 'string') { localStorage. ...

  6. css-包含块

    在CSS中,有事一个元素的位置和尺寸的计算都相对于一个矩形,这个矩形被称作包含块.包含块是一个相对的概念,比如 子元素的初始化布局总是在父元素的左上角,这就是一个相对的概念.其中父元素就是一个参照物, ...

  7. Oracle常用操作【自己的练习】

    Oracle查询的时候条件要用单引号包裹,不能用双引号;Oracle的in子查询里面的值最多有1000个........ 连接orcl数据库 C:\Windows\system32@orcl as s ...

  8. 集合-LinkList

    参考:http://www.cnblogs.com/skywang12345/p/3308807.html Consumer.class   消费者接口 参考:https://www.jianshu. ...

  9. 标准C程序设计七---02

    Linux应用             编程深入            语言编程 标准C程序设计七---经典C11程序设计    以下内容为阅读:    <标准C程序设计>(第7版) 作者 ...

  10. python多线程(二)

    原文:http://blog.sina.com.cn/s/blog_4b5039210100esc1.html 基础不必多讲,还是直接进入python. Python代码代码的执行由python虚拟机 ...