📄 client.cpp
字号:
// 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 + -