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. 【二叉树】hdu 1710 Binary Tree Traversals

    acm.hdu.edu.cn/showproblem.php?pid=1710 [题意] 给定一棵二叉树的前序遍历和中序遍历,输出后序遍历 [思路] 根据前序遍历和中序遍历递归建树,再后续遍历输出 m ...

  2. mysql 插入replace改变原有数据某些字段

    完整原型:(主要看下面例子) replace into rpt_ci_cinema_seller_shift_dt ( BIZ_DATE,CINEMA_CD,SELLER_CD,LOCATION_CD ...

  3. charts 画折线图

    主题:指定日期内,不同地区的发布信息的数量的变化曲线 数据库是mongod 数据是58同城的发布的信息 整体思路: 1由于从数据库中拿到的数据,格式等方面并不一样能完全满足需求,需要对数据库中的数据进 ...

  4. 前端开发之html篇

    一.什么是html? 1.我们说socket网络编程的时候,提到过一个cs模型,就是客户端—服务端模型,前端开发也是基于网络编程,但是这时就应该是bs模型了,是浏览器与服务端的通信. 我们可以模拟一个 ...

  5. ftrace的使用

    This article explains how to set up ftrace and be able to understand how to trace functions. It shou ...

  6. list或map 打印成json 方便调试

    private final Logger logger = Logger.getLogger(this.getClass()); logger.info(JSON.toJSONStringWithDa ...

  7. Day 13 Python 一之helloworld

    直接肝程序吧! """ # 作业六:用户登录测试(三次机会) count = 1 while count <= 3: user = input('请输入用户名: ' ...

  8. elasticsearch入门使用(一)es 6.2.2安装,centos 7

    elasticsearch(一般叫es)是基于Lucene的搜索服务器,提供http协议接口使用json格式数据,也提供相应的客户端,更详细的信息[优点&场景]请百度百科, 以下官网截图,官网 ...

  9. HDU 5636 Shortest Path(Floyd)

    题目链接  HDU5636 n个点,其中编号相邻的两个点之间都有一条长度为1的边,然后除此之外还有3条长度为1的边. m个询问,每次询问求两个点之前的最短路. 我们把这三条边的6个点两两算最短路, 然 ...

  10. GRYZY #13. 拼不出的数

    拼不出的数 lost.in/.out/.cpp [问题描述] 3 个元素的集合 {5, 1, 2} 的所有子集的和分别是 0, 1, 2, 3, 5, 6, 7, 8.发 现最小的不能由该集合子集拼出 ...