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[] = //文件日期填充需要用到的月份表示
{
"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服务器(三)的更多相关文章
- ftp服务器三种模式
一.匿名开放模式(最不安全) 1.[root@localhost ~]# vim /etc/vsftpd/vsftpd.conf (主配置) anonymous_enable=YES //允 ...
- QT实现FTP服务器(二)
QClientThread类的实现: #include "QClientThread.h" #include <QDebug> /******************* ...
- QT实现FTP服务器(一)
QListenSocket类的实现: #include "QListenSocket.h" #include <QTcpSocket> #include <QDe ...
- 【大话QT之十】实现FTP断点续传(需要设置ftp服务器为“PASV”被动接收方式)
应用需求: 网盘开发工作逐步进入各部分的整合阶段,当用户在客户端修改或新增加一个文件时,该文件要同步上传到服务器端对应的用户目录下,因此针对数据传输(即:上传.下载)这一块现在既定了三种传输方式,即: ...
- CentOS6.5下搭建ftp服务器(三种认证模式:匿名用户、本地用户、虚拟用户)
CentOS 6.5下搭建ftp服务器 vsftpd(very secure ftp daemon,非常安全的FTP守护进程)是一款运行在Linux操作系统上的FTP服务程序,不仅完全开源而且免费,此 ...
- Python09作业思路及源码:高级FTP服务器开发(仅供参考)
高级FTP服务器开发 一,作业要求 高级FTP服务器开发 用户加密认证(完成) 多用户同时登陆(完成) 每个用户有不同家目录且只能访问自己的家目录(完成) 对用户进行磁盘配额,不同用户配额可不同(完成 ...
- 超简单——自己搭建ftp服务器
自己搭建ftp服务器 之所以没选择serv-u,一是因为收费,虽说网上有破解版,但是使用过程中发现破解版很不稳定,经常异常死掉,随后改选用免费的filezilla. 1软件获取 从百度搜索 FileZ ...
- 文件服务器:FTP服务器详解
文件服务器:FTP服务器 数据传输原理 功能简介 文件的传输与管理 不同等级的用户身份:user.guest.anonymous 实体用户.权限较完整 匿名用户.下载资源的能力 命令记录与日志文件记录 ...
- Linux 搭建FTP服务器
介绍 本章主要介绍在Linux中搭建FTP服务器的过程,需要掌握的要点是配置文件的合理配置. 知识点 在linux中使用的FTP是vsftp FTP可以有三种登入方式分别是: 匿名登录方式:不需要用户 ...
随机推荐
- POJ——2251Dungeon Master(三维BFS)
Dungeon Master Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 25379 Accepted: 9856 D ...
- [BZOJ1589] [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果(tarjan缩点 + 记忆化搜索)
传送门 先用tarjan缩点,再记忆话搜索一下 #include <stack> #include <cstdio> #include <cstring> #inc ...
- Classloader中loadClass()方法和Class.forName()区别
Classloader中loadClass()方法和Class.forName()都能得到一个class对象,那这两者得到的class对象有什么区别呢 1.java类装载的过程 Java类装载有三个步 ...
- OsCache MemCached EhCache
Memcache:分布式内存对象缓存系统,占用其他机子的内存.很多互联网,负载均衡三台(以三台为例)web服务器可以共享一台Memcache的资源.传递的信息以键值对的形式存储.传递的数据要实现序列化 ...
- 欧拉函数(codevs 4939)
题目描述 Description 输入一个数n,输出小于n且与n互素的整数个数 输入描述 Input Description 包含多组数据,n=0时结束 测试数据组数不会很多,不必先打表后输出 输出描 ...
- ADO:防止更新的数据含有单引号而出错
原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] public void Update( string au_lname, string zip,string au ...
- MVC 上传文件的方法
这两天又开始研究MVC了,期间断断续续已经搞了好久了,可是都没坚持下来.囧!这次一定坚持搞出来一个名堂. 废话少说,直接上代码. 前台引擎采用Razor @model System.Web.HttpP ...
- FGrowth算法
一:背景 http://www.cnblogs.com/aijianiula/p/5397857.html 上节中,总结了频繁项集挖掘的最基本算法:Apriori算法.这篇文章写下它的改进算法FGro ...
- Linux下Shell脚本运行程序不输出日志到终端
使用: 脚本路径/脚本名 >/dev/>& 说明: 可以简单的理解/dev/null是Linux下的回收站 >默认是把标准输出重定向 2>&1是把出错输出也定向 ...
- odoo写邮件添加收件人
在任何可以写消息的地方点击鼠标 或者回复消息 写消息的框会聚焦并变大 点击撰写框右上角的弹出窗图标 弹出完整的撰写消息窗口 在红色的地方添加收件 ...