FTP文件传输优化

       FTP传输模式分为PORT(主动模式)和PASV(被动模式),被动模式的工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输。如下图所示:

本文目标优化FTP长连接传输,提高ftp传输速度:

1、每次连接ftp服务器时push只发送图片数据,如果链表内有图片数据,不断开连接quitServer(),继续发送数据;

2、当FTP服务器异常断开时,delete ftp对象调用已分配的对象的析构函数,释放资源;

3、当重新连接ftp服务器时,在创建客服端FTP对象,执行构造函数CFTPManager()时实现连接ftp服务器,用户名、密码、传输方式任务!

4、编译ftp静态库生成libftp.a

源码

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 
#include <sys/socket.h>  
#include <netinet/tcp.h> 
#include <signal.h>
#include <sys/types.h>          /* See NOTES */
#include <net/if.h>

#include "FtpClientLib.h"

using namespace std;


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

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

	if(!strSrc.empty()){
		strArray.push_back(strSrc);
	}

	return FTP_SUCC; 
}

std::string CompositString(std::string ip, int port){
	std::string dst;
	int pos = 1;
	
	while((pos = (int)ip.find_first_of(".")) > 0) {
		dst += ip.substr(0 , pos);
		dst += ",";
		ip = ip.substr(pos + 1, ip.length() - pos - 1); 
	}

	dst += ip;
	dst += ",";
	dst += std::to_string(port/256);
	dst += ",";
	dst += std::to_string(port%256);

	return dst;
}

int ParseString(std::list<std::string> strArray, unsigned long & nPort ,std::string & strServerIp){
	if (strArray.size() < 6 )
		return FTP_FAIL ;

	std::list<std::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 FTP_SUCC;
}

std::string GetLocalIp(){

	int sock_get_ip;
	char ipaddr[50];

	struct   sockaddr_in *sin;
	struct   ifreq ifr_ip;

	if ((sock_get_ip=socket(AF_INET, SOCK_STREAM, 0)) == -1){
		warn("socket create failse...GetLocalIp!/n");
		return "";
	}

	memset(&ifr_ip, 0, sizeof(ifr_ip));
	strncpy(ifr_ip.ifr_name, "eth0", sizeof(ifr_ip.ifr_name) - 1);
	if(ioctl(sock_get_ip, SIOCGIFADDR, &ifr_ip) < 0 )
	{
		return "";
	}
	sin = (struct sockaddr_in *)&ifr_ip.ifr_addr;
	strcpy(ipaddr,inet_ntoa(sin->sin_addr));
	close(sock_get_ip);

	return ipaddr;
}

CFTPManager::CFTPManager(const FTPParams &ftp_params){
	m_cmdSocket = 0;
	m_strResponse = "";
	m_commandStr = "";
	m_nCurrentCommand = 0;
	m_bLogin = false;
	m_strPath = "";
	cycle_cout = 0;

	signal(SIGPIPE, SIG_IGN);
	
	struct hostent *addr_info = NULL;
	addr_info = gethostbyname(ftp_params.ip.c_str());
	if(addr_info == NULL){
		warn("!!! can not fetch serverip from host!\n");
		m_strServerIP = "";
	}else{
		char str[32];
		inet_ntop(addr_info->h_addrtype, addr_info->h_addr, str, sizeof(str));
		m_strServerIP = str;
		printf("Got ServerIP %s\n", str);
	}

	m_nServerPort = ftp_params.port;
	m_strUserName = ftp_params.username;
	m_strPassWord = ftp_params.password;
	m_strPath = ftp_params.path;	

#if 1
		int ret = FTP_SUCC;
	
		printf("===ftp connect to server===\n");
	
		ret = connect2Server();
		if(ret < 0){ 
			warn("!!! ftp connect to server fail!\n");///
			//return FTP_FAIL;
		}
	
		ret = inputUserName();
		if(ret < 0){
			warn("!!! ftp cmd input username fail!\n");
			quitServer();
			//return FTP_FAIL;
		}
	
		ret = inputPassWord();
		if( ret < 0){
			warn("!!! ftp cmd input password fail!\n");
			quitServer();
			//return FTP_FAIL;
		}
	
		ret = setTransferMode(binary);
		if(ret < 0){
			warn("!!! ftp cmd set to binary mode fail!\n");
			quitServer();
			//return FTP_FAIL;
		}
#endif


}

CFTPManager::~CFTPManager(void){
	if(m_cmdSocket > 0){
		Close(m_cmdSocket);
		m_bLogin = false;
	}
}
// ! 连接服务器

FTP_API CFTPManager::connect2Server(){

	int m_retry_times = 0;
	int ret = FTP_SUCC;
	
M_RETRY:
	m_cmdSocket = socket(AF_INET, SOCK_STREAM, 0);
	if(m_cmdSocket <= 0){
		m_retry_times++;
		if(m_retry_times > 3){
			warn("!!! ftp cmd socket create retry limited!\n");
			return FTP_FAIL;
		}
		
		goto M_RETRY;
	}

	//set port reused
	int addruse = 1;
	setsockopt(m_cmdSocket, SOL_SOCKET, SO_REUSEADDR, &addruse, sizeof(addruse));

	//keep alive sets
	int keepAlive = 1; //open keepalive
	int keepIdle = 5; // timeout to start check.
	int keepInterval = 1; // time between to check
	int keepCount = 3; // check total times.

	setsockopt(m_cmdSocket, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
	setsockopt(m_cmdSocket, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
	setsockopt(m_cmdSocket, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
	setsockopt(m_cmdSocket, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

	if(m_strServerIP.empty()){
		warn("!!! do not get valid ip!\n");
		close(m_cmdSocket);
		m_cmdSocket = INVALID_SOCKET;
		return FTP_FAIL;
	}

	if(m_nServerPort <= 0){
		m_nServerPort = FTP_DEFAULT_PORT;
		warn("!!! connect to server:%s,use default port:%d\n",m_strServerIP.c_str(),m_nServerPort);			
	}

	if (Connect(m_cmdSocket, m_strServerIP, m_nServerPort) < 0){		
		warn("!!! connect to server fail!\n");
		m_cmdSocket = INVALID_SOCKET;
		return FTP_FAIL;
	}
	
	m_strResponse = serverResponse(m_cmdSocket);
	trace("@@@@line:%d, Response: %s\n", __LINE__, m_strResponse.c_str());

	ret = parseResponse(m_strResponse);
	if(ret != 220){//ready
		warn("!!! connect to server resp fail,rsp:%d\n",ret);
		shutdown(m_cmdSocket, SHUT_RDWR);
		close(m_cmdSocket);
		m_cmdSocket = INVALID_SOCKET;
		return FTP_FAIL;
	}

	return ret;
}

// !输入用户名
FTP_API CFTPManager::inputUserName(){
	int ret = FTP_SUCC;

	if(m_strUserName.empty()){
		warn("!!! do not get valid username!\n");	
		return FTP_FAIL;
	}
	
	std::string strCommandLine = composeCommand(FTP_COMMAND_USERNAME, m_strUserName);
	if (Send(m_cmdSocket, strCommandLine) < 0){
		warn("!!! send user name to server fail!\n");
		return FTP_FAIL;
	}

	m_strResponse = serverResponse(m_cmdSocket);
	ret = parseResponse(m_strResponse);
	if(ret == 220){
		m_strR
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值