⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.cpp

📁 FTP是文件传输协议英文的简称。本程序介绍了FTP协议的原理和实现方法。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// Client.cpp : Defines the entry point for the console application.
//
/***********************************Drawbacks*********************************************/
/*
1. I did not realize the passive listen method. You'd better write it in your 
client especially hoping to bypass firewall. :|)
2. Retransfering is not satisfied. I just realized the single file's retranfering. If 
you want to realize the retransfering for both file and directory, you should rewrite
the directory searching method. In this client, I wrote DownloadWholeDirectory by 
iterator, here, you should rewrite it by cycle. Using this way, you 
can record all unsent directory in flat. In fact, if you do not care the effective, you 
could write the retransfering in a simple way. LENGTHArray is left for the purpose.
Synchronize(Keep..the same) the directory in server and client, and you can get every file's 
length in server and client. If the length of file in client is less than the specified element 
in LENGTHArray, just retransfer it using DownloadUnfinishedFiles. :|)
*/
//author: cauchy 2005.11.20

#include "stdafx.h"
#include "Client.h"
#include <winsock2.h>
#include <afxsock.h>
#include <assert.H>
#include <stdlib.h>
#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
#include <vector>
#include <algorithm>
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define BUFFER_BLOCK_SIZE 4096
#define DEAL_RETURN_CODE(retCode) {	if((retCode)!=0)	return retCode;}

UINT SERVER_LISTEN_PORT=21;
char SERVER_IP[16]="10.214.50.238";	//Author's IP, for test. Pls replace it as the FTP Server's IP
char MY_IP[16]="10.214.50.124";		//Author's IP, for test. Pls replace it as user's IP

SOCKET commSock;					//For Control Connection
std::vector<std::string> DIRArray; //All directories in current directory.
std::vector<std::string> FILEArray;//All files in current directory.
std::vector<long> LENGTHArray;	   //All files length in current directory.

//Auxiliary Functions
int ClientCommandResolve(const char * commandLine);
int Connect();
int Disconnect();

//Sub-Functions in Client Command
int REST(int timeout);
int PWD();
int RMD(const char* dirname);
int PORT(SOCKET *listenSock);
int TYPEA();
int IsValidLocalFileOrDirectory(const char* name);
int GetResponseCode(int correctCode, std::string& str);
BOOL ResponsedCodeFinished(const std::string& str);

//FTP Client Application Functions
int DIR();
int CWD(const char* dirname);
int MKD(const char* dirname);
int DELE(const char *filename);
int RETR(const char* currentDir, const char* filename);
int STOR(const char* currentDir, const char*filename);
int DeleteWholeDirectory(const char *dirname);
int DownloadWholeDirectory(const char* parentDir, const char *dirname);
int UploadWholeDirectory(const char* parentDir, const char* dirname);
BOOL SendFile(SOCKET listenSock, const char* currentDir, const char*filename);
BOOL ReceiveFile(SOCKET listenSock,const char* currentDir, const char* filename, BOOL bPrint, BOOL bWaitRetCode);
int DownloadUnfinishedFiles(const char *filename);

//return value interpretion
//-1 Exception in socket or file happened.
//0  Correct command and executative successfully.
//1  Bad command or bad return code.

/////////////////////////////////////////////////////////////////////////////
// The one and only application object
CWinApp theApp;
//argv[0]  Module name
//argv[1]  ServerIP
//argv[2]  Port:  Defaultly Port is 21

//command:
//retr filename/dir Download file or whole directory
//stor filename/dir Upload file or whole directory
//del filename/dir Delete file or whole directory
//dir	List all contents in current directory.
//mkdir dirname  Create a directory.
//cd    dirname  Change current working directory.
//bye	quit
//x    retransfer unfinished file

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	std::string str;
	char ch;
	if(argc==1)
		return 1;

	// initialize MFC and print and error on failure
#ifndef RAW_SOCKET
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		cerr << _T("Fatal Error: MFC initialization failed") << endl;
		return 1;
	}
#endif
	if(inet_addr(argv[1])==INADDR_NONE)
	{
		WSADATA data;
		if(WSAStartup(MAKEWORD(2,2),&data)!=0)
			return 0;
		hostent * host=gethostbyname((const char *)argv[1]);
		if(host==NULL)
		{
			cerr<<"Error IP."<<endl;
			return 0;
		}
		sockaddr_in serverAddr;
		serverAddr.sin_addr.S_un.S_addr=htonl(ntohl((*(struct in_addr*)host->h_addr).S_un.S_addr));
		strcpy(SERVER_IP,inet_ntoa(serverAddr.sin_addr));
	}
	else
		strcpy(SERVER_IP,argv[1]);
	if(argc==3)
		SERVER_LISTEN_PORT=atoi(argv[2]);

	if(Connect()!=0)
		return 0;
	while(1)
	{
		cout<<"ftp>";
		cout.flush();
		str="";
		while((ch = getchar())!= '\n')
			str+=ch;
		if(ClientCommandResolve(str.c_str())==-1)
			break;
	}
	return 0;
}

int ClientCommandResolve(const char * commandLine)
{
	char paraCommand[BUFFER_BLOCK_SIZE];
	int  pos=0;
	int iResult;
	int retCode;
	std::string str;
	paraCommand[0]='\0';
	iResult=sscanf(commandLine,"%s",paraCommand);
	if(iResult==EOF)
	{
		cout<<"Error command"<<endl;
		return 0;
	}

	if(strcmp(paraCommand,"retr")==0)		//get file/dir
	{
		pos=strlen(paraCommand);
		iResult=sscanf(commandLine+pos,"%s",paraCommand);
		if(iResult==EOF)
		{
			cout<<"retr filename/directory"<<endl;
			return 1;
		}
		if(std::find(FILEArray.begin(),FILEArray.end(),paraCommand)!=FILEArray.end())
			return RETR(".",paraCommand);
		else if(std::find(DIRArray.begin(),DIRArray.end(),paraCommand)!=DIRArray.end())
		{
			retCode=DownloadWholeDirectory(".", paraCommand);
			DEAL_RETURN_CODE(retCode);
			return CWD("..");			//run to father node
		}
		else
		{
			cout<<"retr filename/directory"<<endl;
			return 1;
		}
	}
	else if(strcmp(paraCommand,"stor")==0)		//store filename/directory
	{
		pos=strlen(paraCommand);
		iResult=sscanf(commandLine+pos,"%s",paraCommand);
		if(iResult==EOF)
		{
			cout<<"stor filename/directory"<<endl;
			return 0;
		}
		iResult=IsValidLocalFileOrDirectory(paraCommand);
		if(iResult==0)
			return STOR(".",paraCommand);
		else
			if(iResult==1)
				return UploadWholeDirectory(".",paraCommand);
			else
			{
				cout<<"Error: stor filename/directory"<<endl;
				return 1;
			}
	}
	else if(strcmp(paraCommand,"del")==0)		//del file or directory
	{
		pos=strlen(paraCommand);
		iResult=sscanf(commandLine+pos,"%s",paraCommand);
		if(iResult==EOF)
		{
			cout<<"retr filename/directory"<<endl;
			return 0;
		}
		if(std::find(DIRArray.begin(),DIRArray.end(),paraCommand)!=DIRArray.end())
		{
			retCode=DeleteWholeDirectory(paraCommand);
			DEAL_RETURN_CODE(retCode);
			retCode=CWD("..");			//run to father node
			DEAL_RETURN_CODE(retCode);
			return RMD(paraCommand);
		}
		else if(std::find(FILEArray.begin(),FILEArray.end(),paraCommand)!=FILEArray.end())
			return DELE(paraCommand);
		else
		{
			cout<<"Error: del filename/directory."<<endl;
			return 1;
		}
	}
	else if(strcmp(paraCommand,"dir")==0)		//dir shared file lists
		return DIR();
	else if(strcmp(paraCommand,"mkdir")==0)		//dir shared file lists
	{
		pos=strlen(paraCommand);
		iResult=sscanf(commandLine+pos,"%s",paraCommand);
		if(iResult==EOF)
		{
			cout<<"Error: mkdir directory"<<endl;
			return 1;
		}
		return MKD(paraCommand);
	}
	else if(strcmp(paraCommand,"cd")==0)		//change working directory
	{
		pos=strlen(paraCommand);
		iResult=sscanf(commandLine+pos,"%s",paraCommand);
		if(iResult==EOF)
		{
			cout<<"Error: cd directory"<<endl;
			return 1;
		}
		return CWD(paraCommand);
	}
	else if(strcmp(paraCommand,"x")==0)		//change working directory
	{
		pos=strlen(paraCommand);
		iResult=sscanf(commandLine+pos,"%s",paraCommand);
		if(iResult==EOF)
		{
			cout<<"Error: cd directory"<<endl;
			return 1;
		}
		return DownloadUnfinishedFiles(paraCommand);
	}
	else if(strcmp(paraCommand,"bye")==0)		//dir shared file lists
	{
		Disconnect();
		return -1;
	}
	else
		cout<<"Error command."<<endl;			//error command
	return 0;
}

int Connect()
{
	WSADATA wsaData;
	sockaddr_in serverAddr;
	char buffer[BUFFER_BLOCK_SIZE+1];
	int retCode;
	std::string str;

	if(WSAStartup(MAKEWORD( 2, 2 ), &wsaData)!=0)
	{
		cerr<<"socket init error"<<endl;
		return -1;
	}

	commSock=socket(AF_INET, SOCK_STREAM,0);
	serverAddr.sin_addr.s_addr=inet_addr(SERVER_IP);
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_port=htons(SERVER_LISTEN_PORT);

	if(connect(commSock,(const sockaddr*)&serverAddr,sizeof(sockaddr))==SOCKET_ERROR)
	{
		cerr<<"connection error!"<<endl;
		closesocket(commSock);
		return -1;
	}
	//1. welcome words
	DEAL_RETURN_CODE(GetResponseCode(220,str));

	//2. input user name
	cout<<"username:";
	strcpy(buffer,"USER ");
	cin>>buffer+5;
	strcat(buffer,"\r\n");
	send(commSock,buffer,strlen(buffer),0);
	//get response code
	DEAL_RETURN_CODE(GetResponseCode(331,str));

	//3. input password
	cout<<"pass:";
	strcpy(buffer,"PASS ");
	cin>>buffer+5;
	strcat(buffer,"\r\n");
	send(commSock,buffer,strlen(buffer),0);
	//get multiple response code
	DEAL_RETURN_CODE(GetResponseCode(230,str));
	
	//4. sys
	strcpy(buffer,"SYST\r\n");
	send(commSock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(215,str));


	//5. rest 100 and rest 0
	retCode=REST(100);
	DEAL_RETURN_CODE(retCode);
	retCode=REST(0);
	DEAL_RETURN_CODE(retCode);
	retCode=DIR();
	return retCode;
}

//for multiple response code
int GetResponseCode(int correctCode,std::string& str)
{
	int retCode;
	char buffer[BUFFER_BLOCK_SIZE+1];
	str="";
	while(1)
	{
		retCode=recv(commSock,buffer,BUFFER_BLOCK_SIZE,0);
		if(retCode==SOCKET_ERROR || retCode==0)
			return -1;
		buffer[retCode]='\0';
		cout<<buffer;
		cout.flush();
		str+=buffer;
		if(ResponsedCodeFinished(str))
		{
			if(atoi(str.c_str())==correctCode)
				return 0;
			else
				return 1;
		}
	}
}

BOOL ResponsedCodeFinished(const std::string& str)
{
	if(str[str.length()-2]!='\r' || str[str.length()-1]!='\n')
		return FALSE;
	if(str[3]!='-')
		return TRUE;
	char code[4];
	int beginCode=atoi(str.c_str());
	itoa(beginCode,code,10);
	std::string::size_type pos=str.rfind(code,str.length()-1);
	return str[pos+3]==' ';
}

int Disconnect()
{
	char buffer[BUFFER_BLOCK_SIZE];
	std::string str;
	strcpy(buffer,"QUIT\r\n");
	send(commSock,buffer,strlen(buffer),0);
	return GetResponseCode(221,str);
}

//-1 SOCKET ERROR
//0  COMMAND SUCCESSFUL
//1  COMMAND FAILED
int TYPEA()
{
	char buffer[BUFFER_BLOCK_SIZE];
	std::string str;
	strcpy(buffer,"TYPE A\r\n");
	cout<<buffer;
	send(commSock,buffer,strlen(buffer),0);
	return GetResponseCode(200,str);
}

int REST(int timeout)
{
	char buffer[BUFFER_BLOCK_SIZE];
	std::string str;
	assert(timeout>=0);
	sprintf(buffer,"REST %d\r\n",timeout);
	cout<<buffer;
	send(commSock,buffer,strlen(buffer),0);
	return GetResponseCode(350,str);
}

int PWD()
{
	char buffer[BUFFER_BLOCK_SIZE];
	std::string str;
	strcpy(buffer,"PWD\r\n");
	cout<<buffer;
	send(commSock,buffer,strlen(buffer),0);
	return GetResponseCode(257,str);
}

int CWD(const char* dirname)
{
	char buffer[BUFFER_BLOCK_SIZE];
	std::string str;
	int retCode;
	sprintf(buffer,"CWD %s\r\n",dirname);
	send(commSock,buffer,strlen(buffer),0);
	retCode=GetResponseCode(250,str);
	DEAL_RETURN_CODE(retCode);
	retCode=DIR();
	DEAL_RETURN_CODE(retCode);
	return 0;
}

int MKD(const char* dirname)
{
	char buffer[BUFFER_BLOCK_SIZE];
	std::string str;
	int retCode;
	sprintf(buffer,"MKD %s\r\n",dirname);
	send(commSock,buffer,strlen(buffer),0);
	retCode=GetResponseCode(257,str);
	DEAL_RETURN_CODE(retCode);
	retCode=PWD();
	DEAL_RETURN_CODE(retCode);
	retCode=DIR();
	DEAL_RETURN_CODE(retCode);
	return 0;
}

int PORT(SOCKET *listenSock)
{
	char buffer[BUFFER_BLOCK_SIZE];
	int retCode;
	std::string ip=MY_IP;
	std::string::size_type pos=0;
	sockaddr_in localAddr;
	int sizeAddr=sizeof(sockaddr);
	UINT dataport;
	std::string str;

	*listenSock=socket(AF_INET, SOCK_STREAM,0);
	localAddr.sin_addr.s_addr=inet_addr(MY_IP);
	localAddr.sin_family=AF_INET;
	localAddr.sin_port=htons(0);
	if(bind(*listenSock,(const struct sockaddr*)& localAddr,sizeAddr)==SOCKET_ERROR)
	{
		cerr<<"Bind error: "<<GetLastError()<<endl;
		return 1;
	}
	listen(*listenSock,5);
	getsockname(*listenSock,(struct sockaddr*)& localAddr,&sizeAddr);
	dataport=ntohs(localAddr.sin_port);
	
	while((pos=ip.find(".", pos))!=std::string::npos)
		ip.replace(pos,1, ",");
	sprintf(buffer,"PORT %s,%d,%d\r\n",ip.c_str(),dataport/256,dataport%256);
	cout<<buffer;
	send(commSock,buffer,strlen(buffer),0);

	return GetResponseCode(200,str);
}

int RETR(const char* currentDir,const char* filename)
{
	char buffer[BUFFER_BLOCK_SIZE];
	int retCode;
	SOCKET listenSock;
	std::string str;
	BOOL bWaitRetCode=TRUE;

	retCode=TYPEA();
	DEAL_RETURN_CODE(retCode);
	retCode=PORT(&listenSock);
	DEAL_RETURN_CODE(retCode);

	sprintf(buffer,"RETR %s\r\n",filename);
	cout<<buffer;
	send(commSock,buffer,strlen(buffer),0);

	retCode=GetResponseCode(150,str);
	DEAL_RETURN_CODE(retCode);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -