ftp 协议分析

File Transfer Protocol(文件传输协议)

使用SOCKET实现 FTP的客户端协议规则:

.h

#pragma once
#include <string>
#include <WinSock2.h>
#include <iostream>
#include <atlstr.h>
#include <vector>


using namespace std;

#pragma comment(lib,"WS2_32.lib")


struct StructUrlInfo{
	string WebUrl;
	string LocUrl;
	string Fname;
};
struct ConFtpInfo 
{
	string Add;
	string User;
	string Pwd;
	int    Port;
	ConFtpInfo(string m_add,string m_user,string m_pwd,int m_port){
		Add=m_add;
		User=m_user;
		Pwd=m_pwd;
		Port=m_port;
	}
};


class BZ_Ftp
{
public:
	BZ_Ftp(void);
	~BZ_Ftp(void);

public:
	SOCKET controlSocket, dataSocket;

public:
	bool   Start(ConFtpInfo m_ConFtpInfo);
	bool   RootFileList(ConFtpInfo m_ConFtpInfo,string & name);//获取根目录文件列表
	bool   GetDirFileList(ConFtpInfo m_ConFtpInfo,string DirName,string &name); //获取传入目录列表
	bool   GetCurrentpath(ConFtpInfo m_ConFtpInfo,string & name);//返回当前路径

	bool   DownFile(ConFtpInfo m_ConFtpInfo,string DownUrl,string FileName,string StorageUrl);//下载单个文件
	bool   GetFileNameSize(ConFtpInfo m_ConFtpInfo,unsigned long  &fsize,string DownUrl,string FileName);//获取单个文件大小
	bool   CreateMultipleDirectory(const CString& szPath);
	bool   DownAllFile(vector<StructUrlInfo>UpdateInfoVec);


	unsigned long   GetDownFileSize();
	unsigned long GFileSize;;
protected:
	int  getStateCode(char* buf);
	bool executeFTPCmd(SOCKET controlSocket, char* buf, int len, int stateCode);
	int  getPortNum(char* buf);
	unsigned long DownFileSize;
	

};

  .cpp

#include "StdAfx.h"
#include "BZ_Ftp.h"
#include <vector>


#define RECVPACK_SIZE 2048
#define MAXBLOCKSIZE 1024


BZ_Ftp::BZ_Ftp(void)
{
	controlSocket=NULL;
	dataSocket=NULL;
}


BZ_Ftp::~BZ_Ftp(void)
{
	closesocket(dataSocket);
	closesocket(controlSocket);
	WSACleanup();
}

bool BZ_Ftp::Start(ConFtpInfo m_ConFtpInfo)
{
	WSADATA dat;
	SOCKADDR_IN serverAddr;
	int dataPort, ret, stateCode;
	char buf[100]={0}, sendBuf[1024]={0};

	if (WSAStartup(MAKEWORD(2,2),&dat)!=0)	
	{
		cout<<"Init Falied: "<<GetLastError()<<endl;
		return false;
	}

	controlSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(controlSocket==INVALID_SOCKET)
	{
		cout<<"Creating Control Socket Failed: "<<GetLastError()<<endl;
		return false;
	}

	serverAddr.sin_family=AF_INET;
	serverAddr.sin_addr.S_un.S_addr=inet_addr(m_ConFtpInfo.Add.c_str());	
	serverAddr.sin_port=htons(m_ConFtpInfo.Port);			
	memset(serverAddr.sin_zero,0,sizeof(serverAddr.sin_zero));

	ret=connect(controlSocket,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
	if(ret==SOCKET_ERROR)
	{
		cout<<"Control Socket connecting Failed: "<<GetLastError()<<endl;
		return false;
	}

	cout<<"Control Socket connecting is success."<<endl;


	recv(controlSocket,buf,100,0);

	cout<<buf;

	if(getStateCode(buf) != 220)
	{
		cout<<"Error: Control Socket connecting Failed"<<endl;
		return false;
	}

	memset(buf,0,100);
	sprintf(buf,"USER %s
",m_ConFtpInfo.User.c_str());
	executeFTPCmd(controlSocket, buf, 100, 331);				//331

	memset(buf,0,100);
	sprintf(buf,"PASS %s
",m_ConFtpInfo.Pwd.c_str());
	executeFTPCmd(controlSocket, buf, 100, 230);			//230
	return true;
}

int BZ_Ftp::getStateCode( char* buf )
{
	int num=0;
	char* p=buf;
	while(p != NULL)
	{
		num=10*num+(*p)-'0';
		p++;
		if(*p==' '||*p=='-')
		{
			break;
		}
	}

	return num;
}

bool BZ_Ftp::executeFTPCmd( SOCKET controlSocket, char* buf, int len, int stateCode )
{
	send(controlSocket, buf, len, 0);
	memset(buf, 0, len);
	recv(controlSocket, buf, 100, 0);
	cout<<buf;
	if(getStateCode(buf) == stateCode||getStateCode(buf)==226||getStateCode(buf)==250||getStateCode(buf)==150)
	{
		return true;
	}
	else
	{
		cout<<"The StateCode is Error!"<<endl;
		return false;
	}
}

int BZ_Ftp::getPortNum( char* buf )
{
	int num1=0,num2=0;
	char* p=buf;
	int cnt=0;
	while( 1 )
	{
		if(cnt == 4 && (*p) != ',')
		{
			num1 = 10*num1+(*p)-'0';
		}
		if(cnt == 5)
		{
			num2 = 10*num2+(*p)-'0';
		}
		if((*p) == ',')
		{
			cnt++;
		}
		p++;
		if((*p) == ')')
		{
			break;
		}
	}
	cout<<"The data port number is "<<num1*256+num2<<endl;
	return num1*256+num2;
}

bool BZ_Ftp::RootFileList(ConFtpInfo m_ConFtpInfo, string &strRes )
{
	char buffer[1024];
	char buf[100];
	int dataPort, ret, stateCode;	
	bool res;

	return 0;
}

bool BZ_Ftp::GetDirFileList( ConFtpInfo m_ConFtpInfo,string DirName,string &strRes )
{
	Start(m_ConFtpInfo);
	
	char buf[100];
	int dataPort;
	SOCKADDR_IN serverAddr;
	memset(buf,0,100);
	sprintf(buf,"PASV
");
	executeFTPCmd(controlSocket, buf, 100, 227);				

	dataPort=getPortNum(buf);
	//???????socket
	dataSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_addr.S_un.S_addr=inet_addr(m_ConFtpInfo.Add.c_str());
	serverAddr.sin_port=htons(dataPort);	

	int ret=connect(dataSocket,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
	if(ret==SOCKET_ERROR)
	{
		cout<<"Data Socket connecting Failed: "<<GetLastError()<<endl;
		system("pause");
		return -1;
	}

	
	memset(buf,0,100);
	sprintf(buf,"CWD %s
",DirName.c_str());//250
	executeFTPCmd(controlSocket, buf, 100, 250);

	
	memset(buf,0,100);
	sprintf(buf,"LIST%s
","");
	executeFTPCmd(controlSocket, buf, 100, 150);						
	memset(buf,0,100);
	char buffer[1024];
	memset(buffer,0,1024);

	while(recv(dataSocket,buffer,100,0)){
		strRes=strRes.append(buffer);
		memset(buffer,0,1024);
	}	

	closesocket(dataSocket);
	closesocket(controlSocket);

	return true;
}

bool BZ_Ftp::GetCurrentpath( ConFtpInfo m_ConFtpInfo,string & name )
{
	Start(m_ConFtpInfo);
	char buf[100];
	string UrlStr;
	memset(buf,0,100);
	sprintf(buf,"PWD
","");
	executeFTPCmd(controlSocket, buf, 100, 257);	

	UrlStr.append(buf);

	int index=UrlStr.find('"');
	int index2=UrlStr.find('"',index+1);

	name=UrlStr.substr(index+1,index2-index-1);

	closesocket(controlSocket);

	return true;
}

bool BZ_Ftp::DownFile( ConFtpInfo m_ConFtpInfo,string DownUrl,string FileName,string StorageUrl )
{
	if (!Start(m_ConFtpInfo))
	{
		return false;
	}
	
	DownFileSize=0;

	char buf[100];
	char buffer[1024];
	memset(buffer,0,1024);

	int dataPort;
	SOCKADDR_IN serverAddr;
	memset(buf,0,100);
	sprintf(buf,"PASV
");

	if(!executeFTPCmd(controlSocket, buf, 100, 227)){

		return false;
	}			

	dataPort=getPortNum(buf);
	//???????socket
	dataSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_addr.S_un.S_addr=inet_addr(m_ConFtpInfo.Add.c_str());	//??
	serverAddr.sin_port=htons(dataPort);	

	int ret=connect(dataSocket,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
	if(ret==SOCKET_ERROR)
	{
		cout<<"Data Socket connecting Failed: "<<GetLastError()<<endl;
		return -1;
	}


	if (DownUrl[0]=='/')
	{
		DownUrl=DownUrl.substr(1,DownUrl.length());
	}



	string UrlStr;
	memset(buf,0,100);
	sprintf(buf,"CWD %s
",DownUrl.c_str());
	if(!executeFTPCmd(controlSocket, buf, 100, 250)){
		return false;
	}	

	memset(buf,0,100);
	sprintf(buf,"TYPE I
");
	if(!executeFTPCmd(controlSocket, buf, 100, 200)){
		return false;
	}				//200

	memset(buf,0,100);
	sprintf(buf,"RETR %s
",FileName.c_str());
	if(!executeFTPCmd(controlSocket, buf, 100, 257)){
		return false;
	}	

	memset(buf,0,100);
	sprintf(buf,"TYPE I
");
	if(!executeFTPCmd(controlSocket, buf, 100, 200)){
		return false;
	}				//200

	//FileUrlCreat(StorageUrl.c_str());
	CreateMultipleDirectory(StorageUrl.c_str());

	string m_FileName;

	if (StorageUrl.length()!=0)
	{
		if (StorageUrl[StorageUrl.length()-1]=='/')
		{
			m_FileName=StorageUrl+FileName.c_str();

		}else{

			m_FileName=StorageUrl+'\'+FileName.c_str();
		}

	}else{

		m_FileName=FileName.c_str();
	}


	FILE * fp = fopen(m_FileName.c_str(),"wb");  
	int err=GetLastError();

	if(NULL == fp )  
	{ 
		printf("Down Fopen File Err Code:%d",err);
		return false;
	}  

	int length = 0; 

	while( 0!= (length = recv(dataSocket,buffer,1024,0)))  
	{  
		printf("recv  %d
",length);  

		if(length < 0)  
		{  	  
			break;  
		}  

		int write_length = fwrite(buffer,sizeof(char),length,fp);  

		DownFileSize=DownFileSize+write_length;

		if (write_length<length)  
		{  

			break;  
		}  

		memset(buffer,0,1024);      
	}  


	fclose(fp);  

	Sleep(100);

	return true;
}

bool BZ_Ftp::GetFileNameSize( ConFtpInfo m_ConFtpInfo,unsigned long &fsize,string DownUrl,string FileName )
{
	Start(m_ConFtpInfo);
	char buf[100];
	
	string UrlStr;
	memset(buf,0,100);
	sprintf(buf,"CWD %s
",DownUrl.c_str());
	if(!executeFTPCmd(controlSocket, buf, 100, 257)){
		return false;
	}	

	memset(buf,0,100);
	sprintf(buf,"SIZE %s
",FileName.c_str());
	if(!executeFTPCmd(controlSocket, buf, 100, 213)){
		return false;
	}


	UrlStr=buf;

	int index=UrlStr.find(" ");

	UrlStr=UrlStr.substr(index+1,UrlStr.length());

	fsize=atoi(UrlStr.c_str());

	return true;
}

unsigned long BZ_Ftp::GetDownFileSize()
{
	return DownFileSize;
}




bool BZ_Ftp::CreateMultipleDirectory( const CString& szPath )
{
	CString strDir(szPath); 
	if (strDir.Right(1) != "\")
	{
		strDir.AppendChar('\');
	}

	vector<CString> vPath;          
	CString strTemp;               
	BOOL bSuccess = FALSE;         


	for (int i=0; i<strDir.GetLength(); ++i)
	{
		
		if (strDir.GetAt(i) != '\') 
		{
			strTemp.AppendChar(strDir.GetAt(i));
		}
		else
		{

			vPath.push_back(strTemp);
			strTemp.AppendChar('\');
		}
	}


	std::vector<CString>::const_iterator vIter;

	for (vIter = vPath.begin(); vIter != vPath.end(); vIter++) 
	{
		//??CreateDirectory????, ??TRUE,????FALSE
		bSuccess = CreateDirectory(*vIter, NULL) ? TRUE : FALSE;    
	}

	return bSuccess;
}

  调用示例:

int _tmain(int argc, _TCHAR* argv[])
{
    ConFtpInfo mConFtpInfo("192.168.1.233","root","root",21);

    BZ_Ftp  mBZ_Ftp;

    mBZ_Ftp.Start(mConFtpInfo);//连接登录FTP

    return 0;      
}

 大家自己可以查阅FPT协议命令 实现更多的功能。 

  协议重点注意:

  21端口 只是ftp登录验证账号密码的端口,验证通过之后,服务端会返回 一个新的数据(也就是端口 num1*256+num2 =新端口) 给客户端 重新连接 ,用这个新的端口就可以进行数据的传输服务。 

     如有疑问欢迎联系我QQ:1930932008   备注博客园

原文地址:https://www.cnblogs.com/xuandi/p/6739032.html