C++ FTP 访问封装类

该文章描述了一个C++实现的FTP文件传输类,包括构造函数、析构函数、初始化、登录、进入远程目录、下载和上传文件等关键操作。类中包含了错误处理和信号屏蔽功能,确保了FTP连接的稳定性和数据传输的正确性。
摘要由CSDN通过智能技术生成

头文件

/*! \file 	PubSleFtp.h
* \version  	1.0		
* \brief  	文件传输功能文件		
* \author						
* \date		2011-1-11	
* \par		修改记录				
*/

#ifndef PUB_SLE_FTP_H_
#define PUB_SLE_FTP_H_

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#ifdef __cplusplus                    
extern "C"                             
{
#endif

// FTP参数使用,其它模块没有
#define MAX_STRING_LENGTH			1024		//最大字符串长
#define FTP_CHECK_DATA_LENGTH 		3				//ftp返回码长


#define ERR_FTP_SEND_USER_INFO_TO_SERVER_FAILED      0xF101 /*向Ftp Server User 账户信息失败*/
#define ERR_FTP_RECV_USER_VALID_RESULT_FAILED        0xF102 /*接收Ftp Server User 验证信息失败*/

#define ERR_FTP_SEND_PWD_TO_SERVER_FAILED            0xF103 /*向Ftp Server Pwd信息失败*/
#define ERR_FTP_RECV_PWD_VALID_RESULT_FAILED         0xF104 /*接收Ftp Server Pwd 验证信息失败*/

#define ERR_FTP_CREATE_SOCKET_FAILED                 0xFF01 /*创建Ftp Socket连接失败*/
#define ERR_FTP_CONNECT_TO_SERVER_FAILED             0xFF02 /*连接至FTP Server 失败*/
#define ERR_FTP_INIT_FAILED                          0xFF03 /*初始化FTP 失败*/

#define ERR_FTP_ENTER_REMOTE_DIR_SEND_REQ_FAILED     0xFF13 /*切换远程路径失败*/
#define ERR_FTP_ENTER_REMOTE_DIR_SEND_RESP_FAILED    0xFF14 /*切换远程路径失败*/


// FTP文件传输参数结构体
typedef struct _ST_FTP_PARAM
{
	char     szFtpIp[MAX_STRING_LENGTH];				//ftp服务器ip
	char     szFtpPort[MAX_STRING_LENGTH];				//ftp服务器端口号
	char     szFtpUser[MAX_STRING_LENGTH] ;			//ftp用户
	char     szFtpPwd[MAX_STRING_LENGTH] ;				//ftp密码
	char     szLocalPath[MAX_STRING_LENGTH] ;			//本地路径
	char     szRemotePath[MAX_STRING_LENGTH] ;		//远程路径
		
}ST_FtpParam;

/*! \class		CPubSleFtp
* \version		1.0			
* \brief  	   文件传输类
* \author		
* \date			2009-09-01
* \par			修改记录	
*/
class CPubSleFtp
{
public:
	/*! \fn CPubSleFtp::CPubSleFtp()
	 * \brief  构造函数
	 * \author 
	 * \date   2009-08-03
	*/	
	CPubSleFtp();
	
	/*! \fn CPubSleFtp::~CPubSleFtp()
	 * \brief  析构函数
	 * \author 
	 * \date   2009-08-03
	*/	
	virtual ~CPubSleFtp();

public:
	
	/*! \fn int SleInitFtpParam(const ST_FtpParam *pstFtpParam)
	 * \brief 		设置FTP信息
	 * \param[in] 	const ST_FtpParam *pstFtpParam ftp参数结构体
	 * \param[out] 	无
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	int SleInitFtpParam(const ST_FtpParam *pstFtpParam);
	
	/*! \fn int SleChangeRemoteDir(改变本地和远程目录)
	 * \param[in] 	const ST_FtpParam *pstFtpParam ftp参数结构体
	 * \param[out] 	无
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2012-01-05
	*/ 
	int SleChangeRemoteDir(const ST_FtpParam *pstFtpParam);

	 /*! \fn int SleFtpFile(const char *pszFileName, bool bDownMode)
	 * \brief 		FTP文件
	 * \param[in] 	const char * pszFileName   	ftp文件名,路径已在 SleInitFtpParam 配置好,此时配置文件名即可
	 * \param[in] 	bool bDownMode,ftp传输模式,true:下载;false:上传
	 * \param[out] 	无
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	int SleFtpFile(const char *pszFileName, bool bDownMode);

	/*! \fn void FtpBye()
	 * \brief 		关闭连接,在Linux下,使用bye作为关闭的shell命令
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	void 	FtpBye();
	
private:

	/*! \fn int FtpInit()
	 * \brief 		ftp初始化
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	int FtpInit();

	/*! \fn int FtpLogin()
	 * \brief 		登陆FTP服务器
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	int FtpLogin();

	/*! \fn int EnterRemoteDir()
	 * \brief 		进入远程文件目录
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	int 	EnterRemoteDir();

	/*! \fn int DownLoad(const char *pszFileName)
	 * \brief 		下载文件
	 * \param[in] 	const char *pszFileName  	文件名
	 * \param[out] 	无
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 	
	int 	DownLoad(const char *pszFileName) ;

	/*! \fn int UpLoad(const char *pszFileName)
	 * \brief 		上传文件
	 * \param[in] 	const char *pszFileName  	文件名
	 * \param[out] 	无
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	int 	UpLoad(const char *pszFileName) ;

	
	/*! \fn void DeleteAD(const char *pszStr, int iStrLen, char *pszRetStr)
	 * \brief 		删除回车换行
	 * \param[in] 	const char *pszStr  被处理的字符串
	 * \param[in] 	int iStrLen  	字符串长度
	 * \param[out] 	char *pszRetStr	处理后的字符串
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 		2009-09-01
	*/ 
	void 	DeleteAD(const char *pszStr, int iStrLen,  char *pszRetStr);

	/*! \fn int GetPort(const char *pszRxBuf)
	 * \brief 		获取传输端口号
	 * \param[in] 	const char *pszRxBuf  	字符串指针,指向Ftp服务器返回的端口号
	 * \return 		int 			传输端口号
	 * \author 		
	 * \date 			2009-09-01
	*/ 
	int	GetPort(const char *pszRxBuf);
	
	/*! \fn int WriteFtpData(const char *pszFtpData, int iTxLen) 
	 * \brief 		发送FTP数据
	 * \param[in] 	const char *pszFtpData   发送数据
	 * \param[in] 	int iTxLen  	发送数据长度
	 * \param[out] 	无
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/ 	
	int WriteFtpData(const char *pszFtpData, int iTxLen);

	/*! \fn int ReadFtpData( int iLength,const char *pszCheckData, char *pszFtpData)
	 * \brief 		读取FTP数据
	 * \param[in] 	const char *pszCheckData  返回命令校验码
	 * \param[in] 	int iLength   接收数据长度
	 * \param[out] 	char *pszFtpData  接收数据
	 * \return 		int   0 成功, -1 失败
	 * \author 		
	 * \date 			2009-09-01
	*/
	int ReadFtpData( int iLength,const char *pszCheckData, char *pszFtpData) ;
	
private:

	ST_FtpParam 		m_stFtpParam;							/*ftp参数*/  
	struct	sockaddr_in m_stSockAddr;			            	/*socket addr struct*/  
	int 				m_iSocket;								/*控制SOCKET*/  
	int 				m_iSocketSer;							/*传输SOCKET*/  
	sigset_t			m_stOldMask;							/*ftp屏蔽信号*/

	unsigned int m_randSeed ;
	int FtpGetTmpFileName (char * pFileName, char * pTmpFileName) ;
	int FtpRename (char * pFromName, char *pToName) ;
	int FtpGetSize (const char * pServerFileName);

};

#ifdef __cplusplus 		 
}
#endif/*__cplusplus*/

#endif /*PUB_SLE_FTP_H_*/

源文件

#include "PubSleFtp.h"
#include "PubSleFtpDef.h"
#include "time.h"
#include "stdlib.h"
#include "stdio.h"
#include <netdb.h>


/*! \fn CPubSleFtp::CPubSleFtp()
 * \brief  构造函数
 * \author 
 * \date   2009-08-03
 */

bool isIPAddressValid(const char* pszIPAddr) {
	if (!pszIPAddr)
		return false; //若pszIPAddr为空
	char IP1[100], cIP[4];
	int len = strlen(pszIPAddr);
	int i = 0, j = len - 1;
	int k, m = 0, n = 0, num = 0;
	//去除首尾空格(取出从i-1到j+1之间的字符):
	while (pszIPAddr[i++] == ' ')
		;
	while (pszIPAddr[j--] == ' ')
		;

	for (k = i - 1; k <= j + 1; k++) {
		IP1[m++] = *(pszIPAddr + k);
	}
	IP1[m] = '\0';

	char *p = IP1;

	while (*p != '\0') {
		if (*p == ' ' || *p < '0' || *p > '9')
			return false;
		cIP[n++] = *p; //保存每个子段的第一个字符,用于之后判断该子段是否为0开头

		int sum = 0;  //sum为每一子段的数值,应在0到255之间
		while (*p != '.' && *p != '\0') {
			if (*p == ' ' || *p < '0' || *p > '9')
				return false;
			sum = sum * 10 + *p - 48;  //每一子段字符串转化为整数
			p++;
		}
		if (*p == '.') {
			if ((*(p - 1) >= '0' && *(p - 1) <= '9')
					&& (*(p + 1) >= '0' && *(p + 1) <= '9')) //判断"."前后是否有数字,若无,则为无效IP,如“1.1.127.”
				num++;  //记录“.”出现的次数,不能大于3
			else
				return false;
		};
		if ((sum > 255) || (sum > 0 && cIP[0] == '0') || num > 3)
			return false;  //若子段的值>255或为0开头的非0子段或“.”的数目>3,则为无效IP

		if (*p != '\0')
			p++;
		n = 0;
	}
	if (num != 3)
		return false;
	return true;
}

CPubSleFtp::CPubSleFtp() {
	m_iSocket = -1;
	m_iSocketSer = -1;
	memset(&m_stFtpParam, 0, sizeof(m_stFtpParam));

	m_randSeed = time(NULL);

	srand(m_randSeed);
}

/*! \fn CPubSleFtp::~CPubSleFtp()
 * \brief  析构函数
 * \author 
 * \date   2009-08-03
 */
CPubSleFtp::~CPubSleFtp() {

}

/*! \fn int SleInitFtpParam(const ST_FtpParam *pstFtpParam)
 * \brief 		设置FTP信息
 * \param[in] 	pstFtpParam   	ftp参数结构体
 * \param[out] 	无
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 			2009-09-01
 */
int CPubSleFtp::SleInitFtpParam(const ST_FtpParam *pstFtpParam) {
	int iRet = 0xFFFF;

	memcpy(&m_stFtpParam, pstFtpParam, sizeof(m_stFtpParam));

	iRet = FtpInit();
	if (0 != iRet)  //ftp初始化
			{
		return iRet;
	}

	iRet = FtpLogin();
	if (0 != iRet) //ftp登录
			{
		return iRet;
	}

	iRet = EnterRemoteDir();
	if (0 != iRet) 	//进入ftp远程目录
			{
		return iRet;
	}

	return 0;
}

/*! \fn int SleChangeRemoteDir(改变本地和远程目录)
 * \param[in] 	const ST_FtpParam *pstFtpParam ftp参数结构体
 * \param[out] 	无
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 			2011-01-05
 */
int CPubSleFtp::SleChangeRemoteDir(const ST_FtpParam *pstFtpParam) {
	int iRet = 0xFFFF;

	memcpy(&m_stFtpParam, pstFtpParam, sizeof(m_stFtpParam));

	iRet = EnterRemoteDir();

	if (0 != iRet) 	//进入ftp远程目录
			{
		return iRet;
	}

	return iRet;

}

/*! \fn int SleFtpFile(const char *pszFileName, bool bDownMode)
 * \brief 		FTP文件
 * \param[in] 	pszFileName   	ftp文件名
 * \param[in] 	bool bDownMode,ftp传输模式,true:下载;false:上传
 * \param[out] 	无
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 			2009-09-01
 */
int CPubSleFtp::SleFtpFile(const char *pszFileName, bool bDownMode) {
	if (NULL == pszFileName) {	 
		return -1;
	}

	if (bDownMode)	//下载
	{
		if (0 != DownLoad(pszFileName)) {	 
			return -1;
		} else {
		}
	} else // 上传
	{
		if (0 != UpLoad(pszFileName)) {		 
			return -1;
		} else {
		}
	}

	/*FTP成功返回	*/
	return 0;
}

/*! \fn int FtpInit()
 * \brief 	ftp初始化
 * \return 	int   0 成功, -1 失败
 * \author 	
 * \date 		2009-09-01
 */
int CPubSleFtp::FtpInit() {
	int iRet = 0;

	if (m_iSocket > 0)
		close(m_iSocket);

	/*< FTP过程中需要屏蔽信号*/
	sigset_t newmask;
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGINT);
	sigaddset(&newmask, SIGPIPE);
	sigprocmask(SIG_BLOCK, &newmask, &m_stOldMask);

	if ((m_iSocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

		return ERR_FTP_CREATE_SOCKET_FAILED;
	}

	memset(&m_stSockAddr, 0x00, sizeof(m_stSockAddr));
	m_stSockAddr.sin_family = AF_INET;
	char     szFtpIp[MAX_STRING_LENGTH] = {0};				//ftp服务器ip
	if (isIPAddressValid(m_stFtpParam.szFtpIp))
		memcpy(szFtpIp,m_stFtpParam.szFtpIp,strlen(m_stFtpParam.szFtpIp));
	else {
		int i;
		struct hostent *he;
		struct in_addr **addr_list;

		if ((he = gethostbyname(m_stFtpParam.szFtpIp)) == NULL) { // get the host info
			return ERR_FTP_CONNECT_TO_SERVER_FAILED;
		}

		addr_list = (struct in_addr **) he->h_addr_list;
		for (i = 0; addr_list[i] != NULL; i++) {

			memcpy(szFtpIp,inet_ntoa(*addr_list[i]),strlen(inet_ntoa(*addr_list[i])));
			break;
		}
	}

	m_stSockAddr.sin_addr.s_addr = inet_addr(szFtpIp);
	m_stSockAddr.sin_port = htons(atoi(m_stFtpParam.szFtpPort)); /* Port of FTP */

	if (-1
			== connect(m_iSocket, (struct sockaddr *) &m_stSockAddr,
					sizeof(m_stSockAddr))) {

		close(m_iSocket);
		m_iSocket = -1;
		return ERR_FTP_CONNECT_TO_SERVER_FAILED;
	}

	/* 220-Connect successfully */
	//usleep(10000);  //服务器应答 “220 x2100-1 FTP server ready.”需要一定的时间延迟
	time_t tmStart = time(NULL);
	while (time(NULL) <= tmStart + 60) {
		char szRxBuf[MAX_STRING_LENGTH];
		memset(szRxBuf, 0, sizeof(szRxBuf));

		iRet = ReadFtpData(MAX_STRING_LENGTH, (char *) FTP_TRANSMIT_CONNECT,
				szRxBuf);
		if (0 != iRet) {
		
			usleep(3000);
			continue;
		}

		return 0;
	}

	return ERR_FTP_INIT_FAILED;
}

/*! \fn int FtpLogin()
 * \brief 	登陆FTP服务器
 * \return 	int   0 成功, -1 失败
 * \author 	
 * \date 		2009-09-01
 */
int CPubSleFtp::FtpLogin() {
	int iRet = 0xFFFF;
	char szBuffer[MAX_STRING_LENGTH];

	/*发送用户名*/
	char szUser[100];

	memset(szBuffer, 0, sizeof(szBuffer));
	memset(szUser, 0, sizeof(szUser));

	sprintf(szUser, "USER %s\r\n", m_stFtpParam.szFtpUser);
	iRet = WriteFtpData(szUser, strlen(szUser));
	if (iRet != 0) {
		return ERR_FTP_SEND_USER_INFO_TO_SERVER_FAILED;
	}

	/* 331-User name is ok */
	iRet = ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_USER_NAME,
			szBuffer);
	if (0 != iRet) {
		return ERR_FTP_RECV_USER_VALID_RESULT_FAILED;
	}

	/*发送密码*/
	char szPwd[100];
	memset(szPwd, 0, sizeof(szPwd));

	sprintf(szPwd, "PASS %s\r\n", m_stFtpParam.szFtpPwd);
	iRet = WriteFtpData(szPwd, strlen(szPwd));
	if (0 != iRet) {
		return ERR_FTP_SEND_PWD_TO_SERVER_FAILED;
	}

	memset(szBuffer, 0, sizeof(szBuffer));
	/* 230-Login successfully */
	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_PWD,
					szBuffer)) {
		return ERR_FTP_RECV_PWD_VALID_RESULT_FAILED;
	}

	/*二进制传输*/
	iRet = WriteFtpData((char *) "TYPE I\r\n", 8);
	if (0 != iRet) {
		return 0xF105;
	}

	memset(szBuffer, 0, sizeof(szBuffer));
	iRet = ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_CHANGE_MODE,
			szBuffer);
	/* 200-Chang mode successfully */
	if (0 != iRet) {
		return 0xF106;
	}

	return 0;
}

/*! \fn int EnterRemoteDir()
 * \brief 	进入远程文件目录
 * \return 	int   0 成功, -1 失败
 * \author 	
 * \date 		2009-09-01
 */
int CPubSleFtp::EnterRemoteDir() {

	int iRet = 0;

	char szBuffer[MAX_STRING_LENGTH];
	memset(szBuffer, 0, sizeof(szBuffer));

	sprintf(szBuffer, "CWD %s\r\n", m_stFtpParam.szRemotePath);
	iRet = WriteFtpData(szBuffer, strlen(szBuffer));
	if (0 != iRet) {
		return ERR_FTP_ENTER_REMOTE_DIR_SEND_REQ_FAILED;
	}

	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_CWD,
					szBuffer)) {
		return ERR_FTP_ENTER_REMOTE_DIR_SEND_RESP_FAILED;
	}

	return 0;
}

/*! \fn int DownLoad(const char *pszFileName)
 * \brief 		下载文件
 * \param[in] 	pszFileName   	文件名
 * \param[out] 	无
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 		2009-09-01
 */
int CPubSleFtp::DownLoad(const char *pszFileName) {
	/*打开本地存放目录*/
	DIR *pDir;
	char szTemp226Buf[1024] = { 0 };
	char *p = NULL; 

	if ((pDir = opendir(m_stFtpParam.szLocalPath)) == NULL) {
		mkdir(m_stFtpParam.szLocalPath, S_IRWXU | S_IRGRP);
	}

	if (NULL != pDir) {
		closedir(pDir);
	}

	char szBuffer[4 * 1024];

	int iFileSize = FtpGetSize(pszFileName); /* Size of file that will be got */
	if (iFileSize <= 0)
		return -1;

	WriteFtpData((char *) "PASV\r\n", 6);

	/* 227-Entering passive mode */
	memset(szBuffer, 0, sizeof(szBuffer));
	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_PASSIVE_MODE,
					szBuffer)) {
		return -2;
	}

	if ((m_iSocketSer = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		return -3;
	}

	m_stSockAddr.sin_port = GetPort(szBuffer);
	if (connect(m_iSocketSer, (const struct sockaddr *) &m_stSockAddr,
			sizeof(m_stSockAddr))) {
		close(m_iSocketSer);

		return -4;
	}

	// printf ("Connect Data Socket [%d]\n" , m_iSocketSer) ;
	/*创建文件*/
	FILE *pfRecvFile = NULL; /* Receive file */
	sprintf(szBuffer, "%s/%s", m_stFtpParam.szLocalPath, pszFileName);
	if ((pfRecvFile = fopen(szBuffer, "wb")) == NULL) {
		close(m_iSocketSer);
		return -5; /* Open file to receive fail */
	}

	sprintf(szBuffer, "RETR %s/%s\r\n", m_stFtpParam.szRemotePath, pszFileName);
	WriteFtpData(szBuffer, strlen(szBuffer));

	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_RETR,
					szBuffer)) {
		fclose(pfRecvFile);
		close(m_iSocketSer);
		return -6;
	}
	
	memset(szTemp226Buf, 0, sizeof(szTemp226Buf));
	sprintf(szTemp226Buf, "%s", szBuffer);

	int iTransFileSize = 0;
	int iLength = 0; /* Length of data that be sent */

	int iSelectTimeout = 120;
	struct timeval stTimeOut;

	int iErrorCount = 0;
	while (true)
	{
		stTimeOut.tv_sec = iSelectTimeout;
		stTimeOut.tv_usec = 0;
		fd_set stReadReady;
		FD_ZERO(&stReadReady);
		FD_SET(m_iSocketSer, &stReadReady);

		int iRet = 0;
		iRet = select(m_iSocketSer + 1, &stReadReady, NULL, NULL, &stTimeOut);

		if (iRet == 0) {
			if (iErrorCount < 2) {
				iErrorCount++;
				usleep(3000);
				continue;
			}

			// timeout or Error.
			break;
			//	continue ;
		}

		if (iRet < 0) {
			// Error Occurs
			if ((errno == EINTR || errno == EAGAIN) && iErrorCount < 2) {
				iErrorCount++;
				usleep(3000);
				continue;
			} else
				break;
		}

		if (FD_ISSET(m_iSocketSer, &stReadReady) == false) {
			break;
		}

		// Read Bytes
		iLength = recv(m_iSocketSer, szBuffer, sizeof(szBuffer), MSG_DONTWAIT);


		if (iLength <= 0) {
			printf("[%s][%d] recv Error = [%d], [%s]\n", __FUNCTION__, __LINE__,
			errno, strerror(errno));

			if (errno == EINTR || errno == EAGAIN) {
				sleep(1);
				continue;
			}
			break;
		}

		fwrite(szBuffer, iLength, 1, pfRecvFile);
		iTransFileSize += iLength;

		if (iTransFileSize >= iFileSize)
			break;
	}

	printf("[%s][%d] iTransFileSize = [%d], iFileSize = [%d]\n", __FUNCTION__,
			__LINE__, iTransFileSize, iFileSize);

	if (iTransFileSize != iFileSize) {

		close(m_iSocketSer);
		fclose(pfRecvFile);
		return -7; /*文件未传输完 */
	}
	close(m_iSocketSer);
	fclose(pfRecvFile);

	/* 226-End of sending data */
	memset(szBuffer, 0, sizeof(szBuffer));
	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_END,
					szBuffer)) {
		//add by  at 20120809: 为了解决Ftp下载失败的问题
		p = strstr(szTemp226Buf, "226");
		if (p == NULL)
			return -8;
		else
			printf(
					"\n Warning: has receive 226 at the same time for receive 150 \n");
	}

	return 0; //下载成功
}

/*! \fn int UpLoad(const char *pszFileName)
 * \brief 		上传文件
 * \param[in] 	pszFileName   	文件名
 * \param[out] 	无
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 			2009-09-01
 */
int CPubSleFtp::UpLoad(const char *pszFileName) {
	char szTemp226Buf[1024] = { 0 };
	char *p = NULL;  

	/* 227-Entering passive mode */
	WriteFtpData((char *) "PASV\r\n", 6);
	char szBuffer[MAX_STRING_LENGTH];

	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_PASSIVE_MODE,
					szBuffer)) {
		return -1;
	}

	if ((m_iSocketSer = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		printf("[%s][%d]Create socket for data transfer err[%d]!\n", __FILE__,
				__LINE__, errno);
		return -2;
	}

	m_stSockAddr.sin_port = GetPort(szBuffer);
	if (connect(m_iSocketSer, (const struct sockaddr *) &m_stSockAddr,
			sizeof(m_stSockAddr)) == -1) {
		printf("[%s][%d]Connect to transfer port(%d) err[%d]!\n",
		__FILE__, __LINE__, ntohs(m_stSockAddr.sin_port), errno);
		close(m_iSocketSer);
		return -3;
	}

	/*打开本地文件*/
	FILE *pfSendFile = NULL;
	memset(szBuffer, 0, sizeof(szBuffer));
	sprintf(szBuffer, "%s", pszFileName);

	if ((pfSendFile = fopen(szBuffer, "rb")) == NULL) {
		printf("[%s][%d]open local file[%s] err\n", __FILE__, __LINE__,
				szBuffer);
		close(m_iSocketSer);
		return -4;
	}

	char *pFileName = NULL;
	pFileName = strrchr((char*) pszFileName, '/');

	pFileName += 1; // Skip dir /.
	char pTmpFileName[1024];

	memset(pTmpFileName, 0, sizeof(pTmpFileName));

	FtpGetTmpFileName(pFileName, pTmpFileName);

	memset(szBuffer, 0, sizeof(szBuffer));
	sprintf(szBuffer, "STOR ./%s\r\n", pTmpFileName);
	WriteFtpData(szBuffer, strlen(szBuffer));
	/* 150-Opening data connection */
	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_RETR,
					szBuffer)) {
		fclose(pfSendFile);
		close(m_iSocketSer);
		return -5;
	}

	printf("\n the content of buffer after receive 150 : %s \n", szBuffer);

	memset(szTemp226Buf, 0, sizeof(szTemp226Buf));
	sprintf(szTemp226Buf, "%s", szBuffer);

	/*确定文件大小,传输文件*/
	int iLength = 0;
	struct stat buf;
	stat(pszFileName, &buf);
	int iFileSize = buf.st_size;
	int len, n;
	int iSendFileSize = 0;
	while (!feof(pfSendFile)) {
		iLength = fread(szBuffer, 1, MAX_STRING_LENGTH, pfSendFile);
		len = 0;
		n = 0;
		while (iLength != len) {
			n = send(m_iSocketSer, (szBuffer + len), (iLength - len), 0);
			if (n < 0)
				break;
			len += n;
		}
		if (n < 0)
			break;
		iSendFileSize += iLength;
		if (iSendFileSize > iFileSize)
			break;
	}

	if (iSendFileSize < iFileSize) {
		printf("[%s][%d]sendfile size[%d] < filesize[%d]\n", __FILE__, __LINE__,
				iSendFileSize, iFileSize);
		fclose(pfSendFile);
		close(m_iSocketSer);
		return -6;
	}

	fclose(pfSendFile);
	close(m_iSocketSer);

	/* 226-Transfer complete */
	memset(szBuffer, 0, sizeof(szBuffer));
	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_END,
					szBuffer)) {
		p = strstr(szTemp226Buf, "226");
		if (p == NULL)
			return -7;
		else
			printf(
					"\n Warning: has receive 226 at the same time for receive 150 \n");
	}

	// Get Size of Server File .
	iSendFileSize = FtpGetSize(pTmpFileName);

	if (iSendFileSize != iFileSize) {
		// File Size Error.
		return -8;
	}

	// Try to Rename File .
	iSendFileSize = FtpRename(pTmpFileName, pFileName);

	return iSendFileSize;

	// return 0; /* UpLoad Succuss */
}

/*! \fn void FtpBye()
 * \brief 	关闭连接
 * \return 	int   0 成功, -1 失败
 * \author 	
 * \date 		2009-09-01
 */
void CPubSleFtp::FtpBye() {
	char szBuffer[MAX_STRING_LENGTH];
	memset(szBuffer, 0, sizeof(szBuffer));

	if (m_iSocket > 0) //add by  at 20140210
			{
		WriteFtpData((char *) "QUIT\r\n", 6);
		ReadFtpData(MAX_STRING_LENGTH, (char *) FTP_TRANSMIT_BYE, szBuffer); /* 221-Disconnect successfully */
		close(m_iSocket);
	}

	sigprocmask(SIG_SETMASK, &m_stOldMask, NULL);
	m_iSocket = -1;
}

/*! \fn void DeleteAD(const char *pszStr, int iStrLen, char *pszRetStr)
 * \brief 		删除回车换行
 * \param[in] 	pszStr   	被处理的字符串
 * \param[in] 	iStrLen   	字符串长度
 * \param[out] 	pszRetStr	处理后的字符串
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 		2009-09-01
 */
void CPubSleFtp::DeleteAD(const char *pszStr, int iStrLen, char *pszRetStr) {
	assert(pszStr);
	assert(pszRetStr);

	char *pszStrA, *pszStrD;
	memcpy(pszRetStr, pszStr, iStrLen);
	pszStrA = (char*) strchr(pszRetStr, 0x0A);
	pszStrD = (char*) strchr(pszRetStr, 0x0D);

	if ((NULL != pszStrA) && (NULL != pszStrD)) {
		(pszStrA < pszStrD) ? (*pszStrA = 0x00) : (*pszStrD = 0x00);
	} else {
		if (NULL != pszStrA) {
			*pszStrA = 0x00;
		}

		if (pszStrD) {
			*pszStrD = 0x00;
		}
	}
}

/*! \fn int GetPort(const char *pszRxBuf)
 * \brief 		获取传输端口号
 * \param[in] 	const char *pszRxBuf  	字符串指针,Ftp服务器返回的端口号
 * \param[out] 	无
 * \return 		int 			传输端口号
 * \author 		
 * \date 			2009-09-01
 */
int CPubSleFtp::GetPort(const char *pszRxBuf) {
	char *Lo, *Hi, *End;
	int iPort = 0;
	;

	End = (char*) strrchr(pszRxBuf, ')');
	*End = 0x00;
	Lo = (char*) strrchr(pszRxBuf, ',');
	*Lo = 0x00;
	Hi = (char*) strrchr(pszRxBuf, ',');
	iPort = atoi(Hi + 1) * 256 + atoi(Lo + 1);

	return (htons(iPort));
}

/*! \fn int WriteFtpData(const char *pszFtpData, int iTxLen) 
 * \brief 		发送FTP数据
 * \param[in] 	const char *pszFtpData   发送数据
 * \param[in] 	int iTxLen   	发送数据长度
 * \param[out] 	无
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 			2009-09-01
 */
int CPubSleFtp::WriteFtpData(const char *pszFtpData, int iTxLen) {
	assert(pszFtpData);

	if (send(m_iSocket, pszFtpData, iTxLen, 0) < iTxLen) {
		close(m_iSocket);
		m_iSocket = -1;
		return 0xFF06;
	}

	return 0;
}

/*! \fn int ReadFtpData( int iLength,const char *pszCheckData, char *pszFtpData)
 * \brief 		读取FTP数据
 * \param[in] 	const char *pszCheckData   返回命令校验码
 * \param[in] 	int iLength   	   接收数据长度
 * \param[out] 	char *pszFtpData	接收数据
 * \return 		int   0 成功, -1 失败
 * \author 		
 * \date 			2009-09-01
 */
int CPubSleFtp::ReadFtpData(int iLength, const char *pszCheckData,
		char *pszFtpData) {
	struct timeval stTimeOut;
	stTimeOut.tv_sec = 30;
	stTimeOut.tv_usec = 0;

	int iReadLen = 0;
	time_t tmStartTime = time(NULL);

	while (time(NULL) <= tmStartTime + stTimeOut.tv_sec) {
		if (m_iSocket <= 0) {
			printf("m_iSocket [%d] Failed. \n", m_iSocket);
			return 0xFFFE;
		}

		fd_set stReadReady;
		FD_ZERO(&stReadReady);
		FD_SET(m_iSocket, &stReadReady);

		if (select(m_iSocket + 1, &stReadReady, NULL, NULL, &stTimeOut) <= 0) {
			printf("Select Read Failed. \n");
			if (errno == EAGAIN || errno == EINTR) {
				usleep(3000);
				continue;
			} else
				break;
		}

		if (FD_ISSET(m_iSocket, &stReadReady) == false) {
			printf("FD_ISSET == false. \n");
			if (errno == EAGAIN || errno == EINTR) {
				usleep(3000);
				continue;
			} else
				break;
		}

		// Read 1 Bytes
		int iLen = recv(m_iSocket, pszFtpData + iReadLen,
				1 /*iLength-iReadLen*/, 0);
		if (iLen <= 0) {
			printf("recv Failed iLen = [%d]. \n", iLen);
			if (errno == EAGAIN || errno == EINTR) {
				usleep(3000);
				continue;
			} else
				return -1;
		}

		if (*(pszFtpData + iReadLen) == '\n') // \r\n
				{
			*(pszFtpData + iReadLen + 1) = '\0';
			iReadLen += 1;
			break;
		}
		iReadLen += iLen;
		stTimeOut.tv_sec = 40;
	}

	if (iReadLen <= 0)
		return -2;
	if (memcmp(pszFtpData, pszCheckData, FTP_CHECK_DATA_LENGTH) == 0) {
		return 0;
	} else {


		pszFtpData[3] = '\0';
		// return Error Code.
		return -3;
	}

}

int CPubSleFtp::FtpGetSize(const char * pServerFileName) {
	char szBuffer[MAX_STRING_LENGTH];
	memset(szBuffer, 0, sizeof(szBuffer));

	sprintf(szBuffer, "SIZE %s\r\n", pServerFileName);
	WriteFtpData(szBuffer, strlen(szBuffer));
	if (0
			!= ReadFtpData(sizeof(szBuffer), (char *) FTP_TRANSMIT_FILE_SIZE,
					szBuffer)) {
		return -1;
	}

	/*确定文件大小*/
	char szTempBuf[MAX_STRING_LENGTH];
	memset(szTempBuf, 0, sizeof(szTempBuf));

	DeleteAD(szBuffer, strlen(szBuffer), szTempBuf);
	int iFileSize = atoi(szTempBuf + 4); /* Size of file that will be got */

	return iFileSize;

}

int CPubSleFtp::FtpRename(char * pFromName, char *pToName) {
	// Send RNFR
	char szBuffer[MAX_STRING_LENGTH];
	memset(szBuffer, 0, sizeof(szBuffer));

	sprintf(szBuffer, "RNFR %s\r\n", pFromName);
	WriteFtpData(szBuffer, strlen(szBuffer));
	if (0
			!= ReadFtpData(sizeof(szBuffer),
					(char *) FTP_TRANSMIT_PENDING_FOR_MORE_INFO, szBuffer)) {
		return -1;
	}

	// Send RNTO
	memset(szBuffer, 0, sizeof(szBuffer));

	sprintf(szBuffer, "RNTO %s\r\n", pToName);
	WriteFtpData(szBuffer, strlen(szBuffer));
	if (0
			!= ReadFtpData(sizeof(szBuffer),
					(char *) FTP_TRANSMIT_FILE_ACTION_OK, szBuffer)) {
		return -1;
	}

	return 0;
}

int CPubSleFtp::FtpGetTmpFileName(char * pFileName, char * pTmpFileName) {
	sprintf(pTmpFileName, "%s.tmp%03d", pFileName,
			rand(/*&m_randSeed*/) % 1000);

	return 0;
}

定义头文件

#ifndef PUBSLEFTPDEF_H_
#define PUBSLEFTPDEF_H_

#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <link.h>
#include <time.h>
#include <dirent.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>


//ftp命令返回码,标准的FTP协议
#define  FTP_TRANSMIT_CONNECT			"220"
#define  FTP_TRANSMIT_BYE				"221"
#define  FTP_TRANSMIT_USER_NAME			"331"
#define  FTP_TRANSMIT_PWD				"230"
#define  FTP_TRANSMIT_CHANGE_MODE		"200"
#define  FTP_TRANSMIT_CWD				"250"
#define  FTP_TRANSMIT_FILE_SIZE			"213"
#define  FTP_TRANSMIT_PASSIVE_MODE		"227"
#define  FTP_TRANSMIT_RETR				"150"
#define  FTP_TRANSMIT_END				"226"
#define	 FTP_TRANSMIT_PENDING_FOR_MORE_INFO "350"
#define  FTP_TRANSMIT_FILE_ACTION_OK    "250"


#endif /*PUBSLEFTPDEF_H_*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

设备系统软件集成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值