C++ftpクライアントを実現

22194 ワード

#ifndef CLIENT_H_
#define CLIENT_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define INVALID_SOCKET				-1
#define FTP_API						int
#define MAX_PATH					260
#define trace						printf

#define FTP_PARAM_BASE
#define FTP_DEFAULT_PORT			"21"							//FTP     
#define FTP_DEFAULT_BUFFER			1024*4							//FTP        
#define FTP_DEFAULT_PATH			"/mnt/dvs/"						//FTP      
	
#define FTP_COMMAND_BASE			1000
#define FTP_COMMAND_END				FTP_COMMAND_BASE + 30
#define FTP_COMMAND_USERNAME		FTP_COMMAND_BASE + 1			//   
#define FTP_COMMAND_PASSWORD		FTP_COMMAND_BASE + 2			//  
#define FTP_COMMAND_QUIT			FTP_COMMAND_BASE + 3			//  
#define FTP_COMMAND_CURRENT_PATH	FTP_COMMAND_BASE + 4			//       
#define FTP_COMMAND_TYPE_MODE		FTP_COMMAND_BASE + 5			//       
#define FTP_COMMAND_PSAV_MODE		FTP_COMMAND_BASE + 6			//       
#define FTP_COMMAND_DIR				FTP_COMMAND_BASE + 7			//       
#define FTP_COMMAND_CHANGE_DIRECTORY FTP_COMMAND_BASE + 8			//     
#define FTP_COMMAND_DELETE_FILE		FTP_COMMAND_BASE + 9			//     
#define FTP_COMMAND_DELETE_DIRECTORY FTP_COMMAND_BASE + 10			//     /   
#define FTP_COMMAND_CREATE_DIRECTORY FTP_COMMAND_BASE + 11			//     /   
#define FTP_COMMAND_RENAME_BEGIN    FTP_COMMAND_BASE  +12			//      
#define FTP_COMMAND_RENAME_END      FTP_COMMAND_BASE + 13			//      
#define FTP_COMMAND_FILE_SIZE		FTP_COMMAND_BASE + 14			//       
#define FTP_COMMAND_DOWNLOAD_POS	FTP_COMMAND_BASE + 15			//            
#define FTP_COMMAND_DOWNLOAD_FILE	FTP_COMMAND_BASE + 16			//     
#define FTP_COMMAND_UPLOAD_FILE		FTP_COMMAND_BASE + 17			//     
#define FTP_COMMAND_APPEND_FILE		FTP_COMMAND_BASE + 18			//       	

/*		      
		login2Server
			|
		inputUserName
			|
		inputPassWord
			|
		      
			|
		  quit
*/

class CFTPManager 
{
public :
	
	enum type {
		binary = 0x31,
		ascii,
	};
	
	CFTPManager(void);

	virtual ~CFTPManager(void);
	
	// !      
	FTP_API login2Server(const std::string &serverIP);

	// !     
	FTP_API inputUserName(const std::string &userName);

	// !    
	FTP_API inputPassWord(const std::string &password);

	// !  FTP
	FTP_API quitServer(void);

	// !  : PWD
	const std::string PWD();

	// !       2      ascii    
	FTP_API setTransferMode(type mode);

	// !       
	const std::string Pasv();

	// !   : DIR
	const std::string Dir(const std::string &path);

	// !   : CD
	FTP_API CD(const std::string &path);

	// !    
	FTP_API DeleteFile(const std::string &strRemoteFile);

	// !      /  
	FTP_API DeleteDirectory(const std::string &strRemoteDir);

	// !     /   
	FTP_API CreateDirectory(const std::string &strRemoteDir);

	// !   
	FTP_API Rename(const std::string &strRemoteFile, const std::string &strNewFile);

	// !      
	long getFileLength(const std::string &strRemoteFile);

	// !    
	void Close(int sock);

	//     
	FTP_API Get(const std::string &strRemoteFile, const std::string &strLocalFile);

	//               
	FTP_API Put(const std::string &strRemoteFile, const std::string &strLocalFile);


private:
	// !           
	const std::string parseCommand(const unsigned int command, const std::string &strParam);

	// !     
	FTP_API Connect(int socketfd, const std::string &serverIP, unsigned int nPort);

	// !        
	const std::string serverResponse(int sockfd);

	// !       
	FTP_API getData(int fd, char *strBuf, unsigned long length);

	// !    
	FTP_API Send(int fd, const std::string &cmd);

	// !    
	FTP_API Send(int fd, const char *cmd, const size_t len);

	// !      
	FTP_API createDataLink(int data_fd);

	// !  PASV          FTP    FTP   IP
	FTP_API ParseString(std::list<:string> strArray, unsigned long & nPort ,std::string & strServerIp);

	//       
	FILE *createLocalFile(const std::string &strLocalFile);

	//      
	FTP_API downLoad(const std::string &strRemoteFile, const std::string &strLocalFile, const int pos = 0, const unsigned int length = 0);

	//     ftp    
	FTP_API parseResponse(const std::string &str);

private:
	//!       
	int		m_cmdSocket;
	
	// !     
	std::string m_strUserName;

	// !      
	std::string m_strPassWord;

	// !    IP
	std::string m_strServerIP;

	// !   Port
	unsigned int m_nServerPort;

	// !         
	std::string m_strResponse;

	// !      
	std::string m_commandStr;

	// !         
	unsigned int m_nCurrentCommand;

	// !      。
	bool	m_bLogin;
};


#endif
#include "../Source/FTPManager.h"

static int SplitString( std::string strSrc, std::list<:string> &strArray , std::string strFlag)
{
	int pos = 1; 

	while((pos = (int)strSrc.find_first_of(strFlag.c_str())) > 0) 
	{
		strArray.insert(strArray.end(), strSrc.substr(0 , pos));
		strSrc = strSrc.substr(pos + 1, strSrc.length() - pos - 1); 
	}

	strArray.insert(strArray.end(), strSrc.substr(0, strSrc.length()));

	return 0; 
}

CFTPManager::CFTPManager(void): m_bLogin(false)
{
	m_cmdSocket = socket(AF_INET, SOCK_STREAM, 0);
	
}

CFTPManager::~CFTPManager(void)
{
	std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, "");

	Send(m_cmdSocket, strCmdLine.c_str());
	close(m_cmdSocket);
	m_bLogin = false;
}

FTP_API CFTPManager::login2Server(const std::string &serverIP)
{
	std::string strPort;
	int pos = serverIP.find_first_of(":");

	if (pos > 0)
	{
		strPort = serverIP.substr(pos + 1, serverIP.length() - pos);
	}
	else
	{
		pos = serverIP.length();
		strPort = FTP_DEFAULT_PORT;
	}

	m_strServerIP = serverIP.substr(0, pos);
	m_nServerPort = atol(strPort.c_str());

	trace("IP: %s port: %d
", m_strServerIP.c_str(), m_nServerPort); if (Connect(m_cmdSocket, m_strServerIP, m_nServerPort) < 0) { return -1; } m_strResponse = serverResponse(m_cmdSocket); printf("@@@@Response: %s", m_strResponse.c_str()); return parseResponse(m_strResponse); } FTP_API CFTPManager::inputUserName(const std::string &userName) { std::string strCommandLine = parseCommand(FTP_COMMAND_USERNAME, userName); m_strUserName = userName; if (Send(m_cmdSocket, strCommandLine) < 0) { return -1; } m_strResponse = serverResponse(m_cmdSocket); printf("Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } FTP_API CFTPManager::inputPassWord(const std::string &password) { std::string strCmdLine = parseCommand(FTP_COMMAND_PASSWORD, password); m_strPassWord = password; if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } else { m_bLogin = true; m_strResponse = serverResponse(m_cmdSocket); printf("Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } } FTP_API CFTPManager::quitServer(void) { std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, ""); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } else { m_strResponse = serverResponse(m_cmdSocket); printf("Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } } const std::string CFTPManager::PWD() { std::string strCmdLine = parseCommand(FTP_COMMAND_CURRENT_PATH, ""); if (Send(m_cmdSocket, strCmdLine.c_str()) < 0) { return ""; } else { return serverResponse(m_cmdSocket); } } FTP_API CFTPManager::setTransferMode(type mode) { std::string strCmdLine; switch (mode) { case binary: strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "I"); break; case ascii: strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "A"); break; default: break; } if (Send(m_cmdSocket, strCmdLine.c_str()) < 0) { assert(false); } else { m_strResponse = serverResponse(m_cmdSocket); printf("@@@@Response: %s", m_strResponse.c_str()); return parseResponse(m_strResponse); } } const std::string CFTPManager::Pasv() { std::string strCmdLine = parseCommand(FTP_COMMAND_PSAV_MODE, ""); if (Send(m_cmdSocket, strCmdLine.c_str()) < 0) { return ""; } else { m_strResponse = serverResponse(m_cmdSocket); return m_strResponse; } } const std::string CFTPManager::Dir(const std::string &path) { int dataSocket = socket(AF_INET, SOCK_STREAM, 0); if (createDataLink(dataSocket) < 0) { return ""; } // std::string strCmdLine = parseCommand(FTP_COMMAND_DIR, path); if (Send(m_cmdSocket, strCmdLine) < 0) { trace("@@@@Response: %s
", serverResponse(m_cmdSocket).c_str()); close(dataSocket); return ""; } else { trace("@@@@Response: %s
", serverResponse(m_cmdSocket).c_str()); m_strResponse = serverResponse(dataSocket); trace("@@@@Response:
%s
", m_strResponse.c_str()); close(dataSocket); return m_strResponse; } } FTP_API CFTPManager::CD(const std::string &path) { assert(m_cmdSocket != INVALID_SOCKET); std::string strCmdLine = parseCommand(FTP_COMMAND_CHANGE_DIRECTORY, path); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } m_strResponse = serverResponse(m_cmdSocket); trace("@@@@Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } FTP_API CFTPManager::DeleteFile(const std::string &strRemoteFile) { assert(m_cmdSocket != INVALID_SOCKET); std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_FILE, strRemoteFile); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } m_strResponse = serverResponse(m_cmdSocket); printf("@@@@Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } FTP_API CFTPManager::DeleteDirectory(const std::string &strRemoteDir) { assert(m_cmdSocket != INVALID_SOCKET); std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_DIRECTORY, strRemoteDir); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } m_strResponse = serverResponse(m_cmdSocket); trace("@@@@Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } FTP_API CFTPManager::CreateDirectory(const std::string &strRemoteDir) { assert(m_cmdSocket != INVALID_SOCKET); std::string strCmdLine = parseCommand(FTP_COMMAND_CREATE_DIRECTORY, strRemoteDir); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } m_strResponse = serverResponse(m_cmdSocket); trace("@@@@Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } FTP_API CFTPManager::Rename(const std::string &strRemoteFile, const std::string &strNewFile) { assert(m_cmdSocket != INVALID_SOCKET); std::string strCmdLine = parseCommand(FTP_COMMAND_RENAME_BEGIN, strRemoteFile); Send(m_cmdSocket, strCmdLine); trace("@@@@Response: %s
", serverResponse(m_cmdSocket).c_str()); Send(m_cmdSocket, parseCommand(FTP_COMMAND_RENAME_END, strNewFile)); m_strResponse = serverResponse(m_cmdSocket); trace("@@@@Response: %s
", m_strResponse.c_str()); return parseResponse(m_strResponse); } long CFTPManager::getFileLength(const std::string &strRemoteFile) { assert(m_cmdSocket != INVALID_SOCKET); std::string strCmdLine = parseCommand(FTP_COMMAND_FILE_SIZE, strRemoteFile); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } m_strResponse = serverResponse(m_cmdSocket); trace("@@@@Response: %s
", m_strResponse.c_str()); std::string strData = m_strResponse.substr(0, 3); unsigned long val = atol(strData.c_str()); if (val == 213) { strData = m_strResponse.substr(4); trace("strData: %s
", strData.c_str()); val = atol(strData.c_str()); return val; } return -1; } void CFTPManager::Close(int sock) { shutdown(sock, SHUT_RDWR); close(sock); sock = INVALID_SOCKET; } FTP_API CFTPManager::Get(const std::string &strRemoteFile, const std::string &strLocalFile) { return downLoad(strRemoteFile, strLocalFile); } FTP_API CFTPManager::Put(const std::string &strRemoteFile, const std::string &strLocalFile) { std::string strCmdLine; const unsigned long dataLen = FTP_DEFAULT_BUFFER; char strBuf[dataLen] = {0}; unsigned long nSize = getFileLength(strRemoteFile); unsigned long nLen = 0; // struct stat sBuf; // // assert(stat(strLocalFile.c_str(), &sBuf) == 0); // trace("size: %d
", sBuf.st_size); FILE *pFile = fopen(strLocalFile.c_str(), "rb"); // assert(pFile != NULL); int data_fd = socket(AF_INET, SOCK_STREAM, 0); assert(data_fd != -1); if (createDataLink(data_fd) < 0) { return -1; } if (nSize == -1) { strCmdLine = parseCommand(FTP_COMMAND_UPLOAD_FILE, strRemoteFile); } else { strCmdLine = parseCommand(FTP_COMMAND_APPEND_FILE, strRemoteFile); } if (Send(m_cmdSocket, strCmdLine) < 0) { Close(data_fd); return -1; } trace("@@@@Response: %s
", serverResponse(m_cmdSocket).c_str()); fseek(pFile, nSize, SEEK_SET); while (!feof(pFile)) { nLen = fread(strBuf, 1, dataLen, pFile); if (nLen < 0) { break; } if (Send(data_fd, strBuf) < 0) { Close(data_fd); return -1; } } trace("@@@@Response: %s
", serverResponse(data_fd).c_str()); Close(data_fd); trace("@@@@Response: %s
", serverResponse(m_cmdSocket).c_str()); fclose(pFile); return 0; } const std::string CFTPManager::parseCommand(const unsigned int command, const std::string &strParam) { if (command < FTP_COMMAND_BASE || command > FTP_COMMAND_END) { return ""; } std::string strCommandLine; m_nCurrentCommand = command; m_commandStr.clear(); switch (command) { case FTP_COMMAND_USERNAME: strCommandLine = "USER "; break; case FTP_COMMAND_PASSWORD: strCommandLine = "PASS "; break; case FTP_COMMAND_QUIT: strCommandLine = "QUIT "; break; case FTP_COMMAND_CURRENT_PATH: strCommandLine = "PWD "; break; case FTP_COMMAND_TYPE_MODE: strCommandLine = "TYPE "; break; case FTP_COMMAND_PSAV_MODE: strCommandLine = "PASV "; break; case FTP_COMMAND_DIR: strCommandLine = "LIST "; break; case FTP_COMMAND_CHANGE_DIRECTORY: strCommandLine = "CWD "; break; case FTP_COMMAND_DELETE_FILE: strCommandLine = "DELE "; break; case FTP_COMMAND_DELETE_DIRECTORY: strCommandLine = "RMD "; break; case FTP_COMMAND_CREATE_DIRECTORY: strCommandLine = "MKD "; break; case FTP_COMMAND_RENAME_BEGIN: strCommandLine = "RNFR "; break; case FTP_COMMAND_RENAME_END: strCommandLine = "RNTO "; break; case FTP_COMMAND_FILE_SIZE: strCommandLine = "SIZE "; break; case FTP_COMMAND_DOWNLOAD_FILE: strCommandLine = "RETR "; break; case FTP_COMMAND_DOWNLOAD_POS: strCommandLine = "REST "; break; case FTP_COMMAND_UPLOAD_FILE: strCommandLine = "STOR "; break; case FTP_COMMAND_APPEND_FILE: strCommandLine = "APPE "; break; default : break; } strCommandLine += strParam; strCommandLine += "\r
"; m_commandStr = strCommandLine; trace("parseCommand: %s
", m_commandStr.c_str()); return m_commandStr; } FTP_API CFTPManager::Connect(int socketfd, const std::string &serverIP, unsigned int nPort) { if (socketfd == INVALID_SOCKET) { return -1; } unsigned int argp = 1; int error = -1; int len = sizeof(int); struct sockaddr_in addr; bool ret = false; timeval stime; fd_set set; ioctl(socketfd, FIONBIO, &argp); // memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(nPort); addr.sin_addr.s_addr = inet_addr(serverIP.c_str()); bzero(&(addr.sin_zero), 8); trace("Address: %s %d
", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); if (connect(socketfd, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1) // TCP { stime.tv_sec = 20; // 1 stime.tv_usec = 0; FD_ZERO(&set); FD_SET(socketfd, &set); if (select(socketfd + 1, NULL, &set, NULL, &stime) > 0) /// 0 -1 { getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len); if (error == 0) { ret = true; } else { ret = false; } } } else { trace("Connect Immediately!!!
"); ret = true; } argp = 0; ioctl(socketfd, FIONBIO, &argp); if (!ret) { close(socketfd); fprintf(stderr, "cannot connect server!!
"); return -1; } //fprintf(stdout, "Connect!!!
"); return 0; } const std::string CFTPManager::serverResponse(int sockfd) { if (sockfd == INVALID_SOCKET) { return ""; } int nRet = -1; char buf[MAX_PATH] = {0}; m_strResponse.clear(); while ((nRet = getData(sockfd, buf, MAX_PATH)) > 0) { buf[MAX_PATH - 1] = '\0'; m_strResponse += buf; } return m_strResponse; } FTP_API CFTPManager::getData(int fd, char *strBuf, unsigned long length) { assert(strBuf != NULL); if (fd == INVALID_SOCKET) { return -1; } memset(strBuf, 0, length); timeval stime; int nLen; stime.tv_sec = 1; stime.tv_usec = 0; fd_set readfd; FD_ZERO( &readfd ); FD_SET(fd, &readfd ); if (select(fd + 1, &readfd, 0, 0, &stime) > 0) { if ((nLen = recv(fd, strBuf, length, 0)) > 0) { return nLen; } else { return -2; } } return 0; } FTP_API CFTPManager::Send(int fd, const std::string &cmd) { if (fd == INVALID_SOCKET) { return -1; } return Send(fd, cmd.c_str(), cmd.length()); } FTP_API CFTPManager::Send(int fd, const char *cmd, const size_t len) { if((FTP_COMMAND_USERNAME != m_nCurrentCommand) &&(FTP_COMMAND_PASSWORD != m_nCurrentCommand) &&(!m_bLogin)) { return -1; } timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; fd_set writefd; FD_ZERO(&writefd); FD_SET(fd, &writefd); if(select(fd + 1, 0, &writefd , 0 , &timeout) > 0) { size_t nlen = len; int nSendLen = 0; while (nlen >0) { nSendLen = send(fd, cmd , (int)nlen , 0); if(nSendLen == -1) return -2; nlen = nlen - nSendLen; cmd += nSendLen; } return 0; } return -1; } FTP_API CFTPManager::createDataLink(int data_fd) { assert(data_fd != INVALID_SOCKET); std::string strData; unsigned long nPort = 0 ; std::string strServerIp ; std::list<:string> strArray ; std::string parseStr = Pasv(); if (parseStr.size() <= 0) { return -1; } //trace("parseInfo: %s
", parseStr.c_str()); size_t nBegin = parseStr.find_first_of("("); size_t nEnd = parseStr.find_first_of(")"); strData = parseStr.substr(nBegin + 1, nEnd - nBegin - 1); //trace("ParseAfter: %s
", strData.c_str()); if( SplitString( strData , strArray , "," ) <0) return -1; if( ParseString( strArray , nPort , strServerIp) < 0) return -1; //trace("nPort: %ld IP: %s
", nPort, strServerIp.c_str()); if (Connect(data_fd, strServerIp, nPort) < 0) { return -1; } return 0; } FTP_API CFTPManager::ParseString(std::list<:string> strArray, unsigned long & nPort ,std::string & strServerIp) { if (strArray.size() < 6 ) return -1 ; std::list<:string>::iterator citor; citor = strArray.begin(); strServerIp = *citor; strServerIp += "."; citor ++; strServerIp += *citor; strServerIp += "."; citor ++ ; strServerIp += *citor; strServerIp += "."; citor ++ ; strServerIp += *citor; citor = strArray.end(); citor--; nPort = atol( (*citor).c_str()); citor--; nPort += atol( (*(citor)).c_str()) * 256 ; return 0 ; } FILE *CFTPManager::createLocalFile(const std::string &strLocalFile) { return fopen(strLocalFile.c_str(), "w+b"); } FTP_API CFTPManager::downLoad(const std::string &strRemoteFile, const std::string &strLocalFile, const int pos, const unsigned int length) { assert(length >= 0); FILE *file = NULL; unsigned long nDataLen = FTP_DEFAULT_BUFFER; char strPos[MAX_PATH] = {0}; int data_fd = socket(AF_INET, SOCK_STREAM, 0); assert(data_fd != -1); if ((length != 0) && (length < nDataLen)) { nDataLen = length; } char *dataBuf = new char[nDataLen]; assert(dataBuf != NULL); sprintf(strPos, "%d", pos); if (createDataLink(data_fd) < 0) { trace("@@@@ Create Data Link error!!!
"); return -1; } std::string strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_POS, strPos); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } trace("@@@@Response: %s
", serverResponse(m_cmdSocket).c_str()); strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_FILE, strRemoteFile); if (Send(m_cmdSocket, strCmdLine) < 0) { return -1; } trace("@@@@Response: %s
", serverResponse(m_cmdSocket).c_str()); file = createLocalFile(std::string(FTP_DEFAULT_PATH + strLocalFile)); assert(file != NULL); int len = 0; int nReceiveLen = 0; while ((len = getData(data_fd, dataBuf, nDataLen)) > 0) { nReceiveLen += len; int num = fwrite(dataBuf, 1, len, file); memset(dataBuf, 0, sizeof(dataBuf)); //trace("%s", dataBuf); trace("Num:%d
", num); if (nReceiveLen == length && length != 0) break; if ((nReceiveLen + nDataLen) > length && length != 0) { delete []dataBuf; nDataLen = length - nReceiveLen; dataBuf = new char[nDataLen]; } } Close(data_fd); fclose(file); delete []dataBuf; return 0; } FTP_API CFTPManager::parseResponse(const std::string &str) { assert(!str.empty()); std::string strData = str.substr(0, 3); unsigned int val = atoi(strData.c_str()); return val; }