0
点赞
收藏
分享

微信扫一扫

ftp 客户端 linux


基本功能介绍

功能

实现

命令

登陆服务器

进入客户端后登陆服务器

open 127.0.0.1

注销、退出

注销服务器,不退出客户端

close

 

直接退出客户端

bye

显示当前目录

显示当前服务器目录

pwd

 

显示当前客户端目录

lpwd

显示当前目录中文件

显示服务器目录中文件

ls

 

显示客户端目录中文件

lls

转换当前目录

转换服务器当前目录

eg:   cd ./weiliqi

 

转换客户端当前目录

eg:   lcd ./weiliqi

创建、删除目录

创建服务器子目录

eg:   mkdir ./weiliqi

 

删除服务器子目录

eg:   rmdir ./weiliqi

文件传输

上传客户端文件

eg:   put client.c

 

下载服务器文件

eg:   get server.c

 

删除服务器文件

eg:   dele server.c

登录服务器,客户端可以执行客户端命令,即:bye,lcd,lls,lpwd.

如果匿名登录服务器,则只能执行客户端命令和下载文件等命令,即:close,bye,lcd,lls,lpwd,cd,pwd,ls,get.

2.重要套接口函数

 

Socket函数:

#include<sys/socket.h>

int socket(int family,int type,int protocol);

返回非负描述字则成功,-1出错。

family指明协议族(IPv4、IPv6或Unix),type表示套接口的类型,protocol一般设置为0。

 

Connect函数:

#include<sys/socket.h>

int connect(int sockfd,const struct sockaddr * servaddr, socklen_t addrlen);

返回0成功,-1出错。

Sockfd是由socket函数返回的套接口描述字,第二、第三个参数分别是一个指向套接口地址结构的指针和该结构的大小。地址结构必须含有服务器的IP地址和端口号。

 

Bind函数

#include<sys/socket.h>

int bind(int sockfd,const struct sockaddr * myaddr, socklen_t addrlen);

返回0成功,-1出错。

第二个参数是一个指向特定协议的地址结构的指针,第三个参数是该地址结构的长度。这个函数给套接口分配一个协议地址,协议地址的含义取决于协议本身。

 

Listen函数:

#include<sys/socket.h>

int listen(int sockfd,int bavklog);

返回0成功,-1出错。

第二个参数规定了内核为此套接口排队的最大连接个数。函数listen只被服务器调用,将未连接的套接口转换成被动套接口,指示内核应接受指向此套接口的连接请求。调用此函数可使套接口从CLOSED状态转换到LISTEN状态。

 

Accept函数:

#include<sys/socket.h>

int accept(int sockfd,const struct sockaddr * cliaddr, socklen_t addrlen);

返回非负描述字成功,-1出错。

此函数由服务器调用,从已完成连接队列头返回下一个已完成连接。若已完成连接队列为空,则进程睡眠。参数cliaddr和addrlen用来返回连接对方进程(客户)的协议地址。

 

Close函数:

#include<unistd.h>

int close(int sockfd);

套接口的close缺省功能是将套接口做上“已关闭”标记,并立即返回到进程。这个套接口描述字不能再为进程所用。

 

Shutdown函数:

#include<sys/socket.h>

int shutdown(int s,int how);

成功返回0,否则返回-1。

该函数调用将导致socket描述符s所指的全双工socket连接被部分或全部关闭。

 

Getsockopt和setsockopt函数;

#include<sys/socket.h>

int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen);

int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t *optlen);

sockfd必须指向一个打开的套接字,level指定系统中解释选项的代码:普通套接口代码或特定于协议的代码;optval是一个指向变量的指针。

 

Recv和send函数:

#include<sys/socket.h>

ssize_t rect(int sockfd,void * buff,size_t nbytes,int flags);

ssize_t send(int sockfd,const void * buff,size_t nbytes,int flags);

成功则返回读入或写出的字节数,出错返回-1。

这两个函数和标准的read和write函数很类似,只是多了一个附加的参数flags。

 

3.文件I/O与高级文件操作函数

open函数:

#include<sys/types.h>

#include<sys/stat.h>

#include<fcnt1.h>

int open(const char *pathname,int flags,…mode_t mode);

打开(或创建)文件失败返回-1。

第一个参数pathname是要打开(或创建)的文件名或含路径的文件名。第二个参数是标志打开的方式,这个参数用来说明这个系统调用的多个选择项。

 

creat函数:

#include<sys/types.h>

#include<sys/stat.h>

#include<fcnt1.h>

int creat(const char *pathname, mode_t mode);

创建文件失败返回-1。

参数含义与open函数相同。

 

read函数:

#include<unist.h>

size_t read(int filedes,void *buff,size_t nbytes);

调用成功返回读取的字节数,返回0表示文件指针在文件尾。错误返回-1。

该函数从文件描述符fd所指的文件中读取nbytes字节到buff所指向的内存缓冲中。

 

write函数:

#include<unist.h>

size_t write(int filedes,void *buff,size_t nbytes);

调用成功返回写入的字节数,返回0表示没有数据要写。错误返回-1。

该函数用来将内存中的数据写入已打开的文件中。

 

opendir/readdir/closedir函数:

#include<sys/types.h>

#include<dirent.h>

DIR * opendir(const char *name);

struct dirent *readdir(DIR *dir);

int closedir(DIR *dir);

opendir函数用来打开一个目录项,readdir读取目录项中的内容,closedir关闭一个已经打开的目录项。

 

chmod函数:

#include<sys/types.h>

#include<sys/stat.h>

int chmod(const char *path, mode_t mode);

调用成功返回0,错误返回-1。

该函数用于修改任何类型的一个现存文件的存取许可权。

 

mkdir/rmdir函数:

#include<sys/types.h>

#include<sys/stat.h>

#include<fcnt1.h>

#include<unistd.h>

int mkdir(const char *pathname, mode_t mode);

int mkdir(const char *pathname);

调用成功返回0,错误返回-1。

mkdir函数用来创建一个新的目录,rmdir删除一个已有的空目录。

 

unlink函数:

#include<unistd.h>

int unlink(const char *pathname);

调用成功返回0,错误返回-1。

该函数用于删除一个目录项或文件。

 

chdir函数:

#include<unistd.h>

int chdir(const char *path);

调用成功返回0,错误返回-1。

该函数用于改变当前工作目录。

二、客户端功能实现与关键函数

1.连接到服务器
函数get_user()和get_pass()得到用户输入的用户名和密码。ftp_login()函数用输入字符与缺省用户名密码、匿名用户密码相比较,如果一致则登陆成功,否则失败。
void get_user()//得到输入用户名
{
char read_buf[64];
printf("User(Press for anonymous): ");
fgets(read_buf, sizeof(read_buf), stdin);
if(read_buf[0]=='\n')
strncpy(user, "anonymous", 9);
else
strncpy(user, read_buf, strlen(read_buf)-1);
}

 

void get_pass()//得到输入密码
{
char read_buf[64];
printf("Password(Press for anonymous): ");
echo_off();//隐藏密码
fgets(read_buf, sizeof(read_buf), stdin);
if(read_buf[0]=='\n')
strncpy(passwd, "anonymous", 9);
else
strncpy(passwd, read_buf, strlen(read_buf)-1);
echo_on();//取消隐藏
printf("\n");
}

int ftp_login()//登陆函数
{
int err;
get_user();
if(ftp_send_cmd("USER ", user, sock_control) < 0)
cmd_err_exit("Can not send message",1);;
err = ftp_get_reply(sock_control);//得到服务器返回
if(err == 331)
{
get_pass();
if(ftp_send_cmd("PASS ", passwd, sock_control) <= 0)
cmd_err_exit("Can not send message",1);
else
err = ftp_get_reply(sock_control);
if(err == 230)//缺省用户
{
return 1;
}
else if(err == 531)//匿名用户
{
return 2;
}
else
{
printf("Password error!\n");
return 0;
}
}
else
{
printf("User error!\n");
return 0;
}
}

函数int xconnect(struct sockaddr_in *s_addr, int type)连接到服务器。
int xconnect(struct sockaddr_in *s_addr, int type)
{
struct timeval(AF_INET, SOCK_STREAM, 0);
if(s < 0)
cmd_err_exit("creat socket error!", 249);

set = setsockopt(s, SOL_SOCKET,SO_RCVTIMEO, &outtime,sizeof(outtime));
if(set !=0)
{
printf("set socket %s errno:%d\n",strerror(errno),errno);
cmd_err_exit("set socket", 1);
}

//connect to the server
if (connect(s,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in)) < 0)
{
printf("Can't connect to server %s, port %d\n",\
inet_ntoa(s_addr->sin_addr),ntohs(ftp_server.sin_port));
exit(252);
}
return s;
}

fgets(read_buf, sizeof(read_buf), stdin);
得到用户名和密码的关键函数。读入数据。

int s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
cmd_err_exit("creat socket error!", 249);
创建套接字,如创建成功,socket函数返回非负值。
//connect to the server
if (connect(s,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in)) < 0)
{
printf("Can't connect to server %s, port %d\n",\
inet_ntoa(s_addr->sin_addr),ntohs(ftp_server.sin_port));
exit(252);
}
连接到服务器,如果连接成功,connect函数返回0,如果不成功,返回-1。

int ftp_send_cmd(const char *s1, const char *s2, int sock_fd)
向服务器发送客户端的命令的函数。
int ftp_send_cmd(const char *s1, const char *s2, int sock_fd)
{
char send_buf[256];
int send_err, len;
if(s1)
{
strcpy(send_buf,s1);
if(s2)
{
strcat(send_buf, s2);
strcat(send_buf,"\r\n");
len = strlen(send_buf);
send_err = send(sock_fd, send_buf, len, 0);
}
else
{
strcat(send_buf,"\r\n");
len = strlen(send_buf);
send_err = send(sock_fd, send_buf, len, 0);
}
}
if(send_err < 0)
printf("send() error!\n");
return send_err;
}

接收服务器返回信息函数
//get the server's reply message from sock_fd
int ftp_get_reply(int sock_fd)
{
static int reply_code = 0,count=0;
char rcv_buf[512];
count=read(sock_fd, rcv_buf, 510);
if(count > 0)
reply_code = atoi(rcv_buf);
else
return 0;
while(1)
{
if(count <= 0)
break;
rcv_buf[count]='\0';
printf("%s",rcv_buf);
count=read(sock_fd, rcv_buf, 510);
}
return reply_code;
}
send_err = send(sock_fd, send_buf, len, 0);
send函数发送成功返回字节数大于0,小于0则出错。

int xconnect_ftpdata()
连接服务器数据流函数。
get_sock = socket(AF_INET, SOCK_STREAM, 0);
set = setsockopt(get_sock, SOL_SOCKET,SO_RCVTIMEO, \
&outtime,sizeof(outtime));
set = setsockopt(get_sock, SOL_SOCKET,SO_REUSEADDR, \
&opt,sizeof(opt));
新建套接字传输数据流。
set = bind(get_sock, (struct sockaddr *)&local_host, \
sizeof(local_host));
if(set != 0 && errno == 11)
{
client_port = rand_local_port();
continue;
}
set = listen(get_sock, 1);
用bind、listen函数开启数据流传输。

进行客户端操作关键函数
void open_ftpsrv()//客户端操作函数
{
char usr_cmd[1024];
int cmd_flag;
while(1)
{
printf("ftp_cli>");
fgets(usr_cmd,510,stdin);
fflush(stdin);
if(usr_cmd[0] == '\n')
continue;
usr_cmd[strlen(usr_cmd)-1] = '\0';
cmd_flag = ftp_usr_cmd(usr_cmd);
if(cmd_flag == 15)
{
char *cmd = strchr(usr_cmd,' ');
char dress_ftp[1024];
if(cmd == NULL)
{
printf("command error!\n");
show_help();
return;
}
else
{
while(*cmd == ' ')
cmd++;
}
if(cmd == NULL||cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
char * dr = "127.0.0.1";
strncpy(dress_ftp,cmd,strlen(cmd));
dress_ftp[strlen(cmd)] = '\0';
printf("%s",dress_ftp);
if(dress_ftp == "127.0.0.1")
{
printf("Connect Seccessed!\n");
start_ftp_cmd(dr,DEFAULT_FTP_PORT);
//open成功则调用该函数,该函数与open_ftpsrv()很相似。
}
else
{
printf("Inviable Server Dress!\n");
}
}
}
else
//如果open不成功,则只能进行客户端上的操作,不能进行有关服务器操作
{
switch(cmd_flag)
{
case 11:
local_list();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 12:
local_pwd();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 13:
local_cd(usr_cmd);
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 6://quit
printf("BYE TO WEILIQI FTP!\n");
exit(0);
break;
default:
printf("command error!\n");
show_help();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
}
}
}

}

2.目录文件操作

void ftp_list()
显示服务器当前目录下文件的函数。

int list_sock_data = xconnect_ftpdata();
创建一个新套接字,表示是否连接上服务器的数据。
ftp_send_cmd("LIST", NULL, sock_control);
ftp_get_reply(sock_control);
向服务器发送命令,得到服务器的响应答复。
new_sock = accept(list_sock_data, (struct sockaddr *)&local_host, \
(socklen_t *)&set);
从服务器接收数据(文件信息)。

void ftp_cmd_filename(char * usr_cmd, char * src_file, char * dst_file)
此函数读取客户端命令后的文件名字。在很多命令中,如get,put后要加入上传或下载的文件名字,这个函数解析文件名字信息。

void local_pwd()
显示客户端目录函数。
//print local current directory
void local_pwd()
{
char curr_dir[512];
int size = sizeof(curr_dir);
if(getcwd(curr_dir, size) == NULL)
printf("getcwd failed\n");
else
printf("Current local directory: %s\n", curr_dir);
}
getcwd(curr_dir, size)得到客户端目录。

void ftp_cd(char * usr_cmd)
转换服务器目录函数。
void ftp_cd(char * usr_cmd)
{
char *cmd = strchr(usr_cmd, ' ');
char path[1024];
if(cmd == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd == ' ')
cmd ++;
}
if(cmd == NULL || cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
strncpy(path, cmd, strlen(cmd));
path[strlen(cmd)]='\0';
ftp_send_cmd("CWD ", path, sock_control);
ftp_get_reply(sock_control);
}
}

ftp_send_cmd("CWD ", path, sock_control);
ftp_get_reply(sock_control);
发送转换目录命令给服务器,服务器完成该功能。

创建目录函数void mkdir_srv(char * usr_cmd) 和删除目录函数void rmdir_srv(char * usr_cmd)与void ftp_cd(char * usr_cmd)函数相似,在此不做解释。


函数void local_list()列出客户端文件列表。
void local_list()
{
DIR * dp;
struct dirent *dirp;
if((dp = opendir("./")) == NULL)
{
printf("opendir() error!\n");
return;
}
printf("Local file list:\n");
while((dirp = readdir(dp)) != NULL)
{
if(strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
continue;
printf("%s\n", dirp->d_name);
}
}

转换客户端目录函数
void local_cd(char * usr_cmd)
{
char *cmd = strchr(usr_cmd, ' ');
char path[1024];
if(cmd == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd == ' ')
cmd ++;
}
if(cmd == NULL || cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
strncpy(path, cmd, strlen(cmd));
path[strlen(cmd)]='\0';
if(chdir(path) < 0) //转换目录
printf("Local: chdir to %s error!\n", path);
else
printf("Local: chdir to %s\n", path);
}
}

//主代码完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <curses.h>
#include <termios.h>
#include <sys/stat.h>
#include <fcntl.h>

#define DEFAULT_FTP_PORT 21

extern int h_errno;

char user[64]; //ftp usr
char passwd[64]; //ftp passwd

//ftp server address
struct sockaddr_in ftp_server, local_host;
struct hostent * server_hostent;

int sock_control;

int mode = 1; //ftp mode, 0 is PORT, 1 is PASV;

//echo_off and echo_on for get usr password from stdin
static struct termios stored_settings;
void echo_off(void)
{
struct termios new_settings;
tcgetattr(0,&stored_settings);
new_settings = stored_settings;
new_settings.c_lflag &= (~ECHO);
tcsetattr(0,TCSANOW,&new_settings);
return;
}
void echo_on(void)
{
tcsetattr(0,TCSANOW,&stored_settings);
return;
}

void cmd_err_exit(char * err_msg, int err_code)
{
printf("%s\n", err_msg);
exit(err_code);
}

int fill_host_addr(char * host_ip_addr, struct sockaddr_in * host, int port)
{
if(port <= 0 || port > 65535)
return 254;
bzero(host, sizeof(struct sockaddr_in));
host->sin_family = AF_INET;
if(inet_addr(host_ip_addr) != -1)
{
host->sin_addr.s_addr = inet_addr(host_ip_addr);
}
else
{
if((server_hostent = gethostbyname(host_ip_addr)) != 0)
{
memcpy(&host->sin_addr, server_hostent->h_addr,\
sizeof(host->sin_addr));
}
else return 253;
}
host->sin_port = htons(port);
return 1;
}

int xconnect(struct sockaddr_in *s_addr, int type)
{
struct timeval(AF_INET, SOCK_STREAM, 0);
if(s < 0)
cmd_err_exit("creat socket error!", 249);

//set outtime for the control socket
if(type == 1)
{
outtime.tv_sec = 0;
outtime.tv_usec = 300000;
}
else
{
outtime.tv_sec = 5;
outtime.tv_usec = 0;
}
set = setsockopt(s, SOL_SOCKET,SO_RCVTIMEO, &outtime,sizeof(outtime));
if(set !=0)
{
printf("set socket %s errno:%d\n",strerror(errno),errno);
cmd_err_exit("set socket", 1);
}

//connect to the server
if (connect(s,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in)) < 0)
{
printf("Can't connect to server %s, port %d\n",\
inet_ntoa(s_addr->sin_addr),ntohs(ftp_server.sin_port));
exit(252);
}
return s;
}

//send command to server with sock_fd
int ftp_send_cmd(const char *s1, const char *s2, int sock_fd)
{
char send_buf[256];
int send_err, len;
if(s1)
{
strcpy(send_buf,s1);
if(s2)
{
strcat(send_buf, s2);
strcat(send_buf,"\r\n");
len = strlen(send_buf);
send_err = send(sock_fd, send_buf, len, 0);
}
else
{
strcat(send_buf,"\r\n");
len = strlen(send_buf);
send_err = send(sock_fd, send_buf, len, 0);
}
}
if(send_err < 0)
printf("send() error!\n");
return send_err;
}

//get the server's reply message from sock_fd
int ftp_get_reply(int sock_fd)
{
static int reply_code = 0,count=0;
char rcv_buf[512];
count=read(sock_fd, rcv_buf, 510);
if(count > 0)
reply_code = atoi(rcv_buf);
else
return 0;
while(1)
{
if(count <= 0)
break;
rcv_buf[count]='\0';
printf("%s",rcv_buf);
count=read(sock_fd, rcv_buf, 510);
}
return reply_code;
}

int get_port()
{
char port_respond[512];
char *buf_ptr;
int count,port_num;
ftp_send_cmd("PASV",NULL,sock_control);
count = read(sock_control, port_respond, 510);
if(count <= 0)
return 0;
port_respond[count]='\0';
if(atoi(port_respond) == 227)
{
//get low byte of the port
buf_ptr = strrchr(port_respond, ',');
port_num = atoi(buf_ptr + 1);
*buf_ptr = '\0';
//get high byte of the port
buf_ptr = strrchr(port_respond, ',');
port_num += atoi(buf_ptr + 1) * 256;
return port_num;
}
return 0;
}

int rand_local_port()
{
int local_port;
srand((unsigned)time(NULL));
local_port = rand() % 40000 + 1025;
return local_port;
}

//connect data stream
int xconnect_ftpdata()
{
if(mode)
{
int data_port = get_port();
if(data_port != 0)
ftp_server.sin_port=htons(data_port);
return(xconnect(&ftp_server, 0));
}
else
{
int client_port, get_sock, opt, set;
char cmd_buf[32];
struct timeval(struct sockaddr);
client_port = rand_local_port();
get_sock = socket(AF_INET, SOCK_STREAM, 0);
if(get_sock < 0)
{
cmd_err_exit("socket()", 1);
}

//set outtime for the data socket
outtime.tv_sec = 7;
outtime.tv_usec = 0;
opt = SO_REUSEADDR;
set = setsockopt(get_sock, SOL_SOCKET,SO_RCVTIMEO, \
&outtime,sizeof(outtime));
if(set !=0)
{
printf("set socket %s errno:%d\n",strerror(errno),errno);
cmd_err_exit("set socket", 1);
}
set = setsockopt(get_sock, SOL_SOCKET,SO_REUSEADDR, \
&opt,sizeof(opt));
if(set !=0)
{
printf("set socket %s errno:%d\n",strerror(errno),errno);
cmd_err_exit("set socket", 1);
}

bzero(&local_host,sizeof(local_host));
local_host.sin_family = AF_INET;
local_host.sin_port = htons(client_port);
local_host.sin_addr.s_addr = htonl(INADDR_ANY);
bzero(&local, sizeof(struct sockaddr));
while(1)
{
set = bind(get_sock, (struct sockaddr *)&local_host, \
sizeof(local_host));
if(set != 0 && errno == 11)
{
client_port = rand_local_port();
continue;
}
set = listen(get_sock, 1);
if(set != 0 && errno == 11)
{
cmd_err_exit("listen()", 1);
}
//get local host's ip
if(getsockname(sock_control,(struct sockaddr*)&local,\
(socklen_t *)&addr_len) < 0)
return -1;
snprintf(local_ip, sizeof(local_ip), inet_ntoa(local.sin_addr));
//change the format to the PORT command needs.
local_ip[strlen(local_ip)]='\0';
ip_1 = local_ip;
ip_2 = strchr(local_ip, '.');
*ip_2 = '\0';
ip_2++;
ip_3 = strchr(ip_2, '.');
*ip_3 = '\0';
ip_3++;
ip_4 = strchr(ip_3, '.');
*ip_4 = '\0';
ip_4++;
snprintf(cmd_buf, sizeof(cmd_buf), "PORT %s,%s,%s,%s,%d,%d", \
ip_1, ip_2, ip_3, ip_4, client_port >> 8, client_port&0xff);
ftp_send_cmd(cmd_buf, NULL, sock_control);
if(ftp_get_reply(sock_control) != 200)
{
printf("Can not use PORT mode!Please use \"mode\" change to PASV mode.\n");
return -1;
}
else
return get_sock;
}
}
}


//deal with the "list" command
void ftp_list()
{
int i = 0,new_sock;
int set = sizeof(local_host);
int list_sock_data = xconnect_ftpdata();
if(list_sock_data < 0)
{
ftp_get_reply(sock_control);
printf("creat data sock error!\n");
return;
}
ftp_get_reply(sock_control);
ftp_send_cmd("LIST", NULL, sock_control);
ftp_get_reply(sock_control);
if(mode)
ftp_get_reply(list_sock_data);
else
{
while(i < 3)
{
new_sock = accept(list_sock_data, (struct sockaddr *)&local_host, \
(socklen_t *)&set);
if(new_sock == -1)
{
printf("accept return:%s errno: %d\n", strerror(errno),errno);
i++;
continue;
}
else break;
}
if(new_sock == -1)
{
printf("Sorry, you can't use PORT mode. There is something wrong when the server connect to you.\n");
return;
}
ftp_get_reply(new_sock);
close(new_sock);
}

close(list_sock_data);
ftp_get_reply(sock_control);
}

//get filename(s) from user's command
void ftp_cmd_filename(char * usr_cmd, char * src_file, char * dst_file)
{
int length, flag = 0;
int i = 0, j = 0;
char * cmd_src;
cmd_src = strchr(usr_cmd, ' ');
if(cmd_src == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd_src == ' ')
cmd_src ++;
}
if(cmd_src == NULL || cmd_src == '\0')
{
printf("command error!\n");
}
else
{
length = strlen(cmd_src);
while(i <= length)//be careful with space in the filename
{
if((*(cmd_src+i)) !=' ' && (*(cmd_src+i)) != '\\')
{
if(flag == 0)
src_file[j] = *(cmd_src +i);
else
dst_file[j] = *(cmd_src +i);
j++;
}
if((*(cmd_src+i)) == '\\' && (*(cmd_src+i+1)) !=' ')
{
if(flag == 0)
src_file[j] = *(cmd_src +i);
else
dst_file[j] = *(cmd_src +i);
j++;
}
if((*(cmd_src+i)) == ' ' && (*(cmd_src+i-1)) != '\\')
{
src_file[j] = '\0';
flag = 1;
j = 0;
}
if((*(cmd_src+i)) == '\\' && (*(cmd_src+i+1)) == ' ')
{
if(flag == 0)
src_file[j] = ' ';
else
dst_file[j] = ' ';
j++;
}
i++;
};
}
if(flag == 0)
strcpy(dst_file, src_file);
else
dst_file[j] = '\0';
}

//deal with the "get" command
void ftp_get(char * usr_cmd)
{
int get_sock, set, new_sock, i = 0;
char src_file[512];
char dst_file[512];
char rcv_buf[512];
char cover_flag[3];
struct stat file_info;
int local_file;
int count = 0;
ftp_cmd_filename(usr_cmd, src_file, dst_file);
ftp_send_cmd("SIZE ", src_file, sock_control);
if(ftp_get_reply(sock_control) != 213)
{
printf("SIZE error!\n");
return;
}
if(!stat(dst_file, &file_info))
{
printf("local file %s exists: %d bytes\n", dst_file, (int)file_info.st_size);
printf("Do you want to cover it? [y/n]");
fgets(cover_flag, sizeof(cover_flag), stdin);
fflush(stdin);
if(cover_flag[0] != 'y')
{
printf("get file %s aborted.\n", src_file);
return;
}
}
local_file = open(dst_file, O_CREAT|O_TRUNC|O_WRONLY);
if(local_file < 0)
{
printf("creat local file %s error!\n", dst_file);
return;
}
get_sock = xconnect_ftpdata();
if(get_sock < 0)
{
printf("socket error!\n");
return;
}
set = sizeof(local_host);

ftp_send_cmd("TYPE I", NULL, sock_control);
ftp_get_reply(sock_control);
ftp_send_cmd("RETR ", src_file, sock_control);
if(!mode)
{
while(i < 3)
{
new_sock = accept(get_sock, (struct sockaddr *)&local_host, \
(socklen_t *)&set);
if(new_sock == -1)
{
printf("accept return:%s errno: %d\n", strerror(errno),errno);
i++;
continue;
}
else break;
}
if(new_sock == -1)
{
printf("Sorry, you can't use PORT mode. There is something wrong when the server connect to you.\n");
return;
}
ftp_get_reply(sock_control);
while(1)
{
printf("loop \n");
count = read(new_sock, rcv_buf, sizeof(rcv_buf));
if(count <= 0)
break;
else
{
write(local_file, rcv_buf, count);
}
}
close(local_file);
close(get_sock);
close(new_sock);
ftp_get_reply(sock_control);
}
else
{
ftp_get_reply(sock_control);
while(1)
{
count = read(get_sock, rcv_buf, sizeof(rcv_buf));
if(count <= 0)
break;
else
{
write(local_file, rcv_buf, count);
}
}
close(local_file);
close(get_sock);
ftp_get_reply(sock_control);
}
if(!chmod(src_file, 0644))
{
printf("chmod %s to 0644\n", dst_file);
return;
}
else
printf("chmod %s to 0644 error!\n", dst_file);
ftp_get_reply(sock_control);
}

//deal with "put" command
void ftp_put(char * usr_cmd)
{
char src_file[512];
char dst_file[512];
char send_buf[512];
struct stat file_info;
int local_file;
int file_put_sock, new_sock, count = 0, i = 0;
int set = sizeof(local_host);
ftp_cmd_filename(usr_cmd, src_file, dst_file);
if(stat(src_file, &file_info) < 0)
{
printf("local file %s doesn't exist!\n", src_file);
return;
}
local_file = open(src_file, O_RDONLY);
if(local_file < 0)
{
printf("open local file %s error!\n", dst_file);
return;
}
file_put_sock = xconnect_ftpdata();
if(file_put_sock < 0)
{
ftp_get_reply(sock_control);
printf("creat data sock errro!\n");
return;
}
ftp_send_cmd("STOR ", dst_file, sock_control);
ftp_get_reply(sock_control);
ftp_send_cmd("TYPE I", NULL, sock_control);
ftp_get_reply(sock_control);
if(!mode)
{
while(i < 3)
{
new_sock = accept(file_put_sock, (struct sockaddr *)&local_host, \
(socklen_t *)&set);
if(new_sock == -1)
{
printf("accept return:%s errno: %d\n", strerror(errno),errno);
i++;
continue;
}
else break;
}
if(new_sock == -1)
{
printf("Sorry, you can't use PORT mode. There is something wrong when the server connect to you.\n");
return;
}
while(1)
{
count = read(local_file, send_buf, sizeof(send_buf));
if(count <= 0)
break;
else
{
write(new_sock, send_buf,sizeof(send_buf));
}
}
close(local_file);
close(file_put_sock);
close(new_sock);
}
else
{
while(1)
{
count = read(local_file, send_buf, sizeof(send_buf));
if(count <= 0)
break;
else
{
write(file_put_sock, send_buf,count);
}
}
close(local_file);
close(file_put_sock);
}
ftp_get_reply(sock_control);
}

//call this function to quit
void ftp_quit()
{
ftp_send_cmd("QUIT",NULL,sock_control);
ftp_get_reply(sock_control);
close(sock_control);
}

//close the connection with the server
void close_cli()
{
ftp_send_cmd("CLOSE",NULL,sock_control);
ftp_get_reply(sock_control);
}

//tell the user what current directory is in the server
void ftp_pwd()
{
ftp_send_cmd("PWD", NULL, sock_control);
ftp_get_reply(sock_control);
}

//change the directory in the server
void ftp_cd(char * usr_cmd)
{
char *cmd = strchr(usr_cmd, ' ');
char path[1024];
if(cmd == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd == ' ')
cmd ++;
}
if(cmd == NULL || cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
strncpy(path, cmd, strlen(cmd));
path[strlen(cmd)]='\0';
ftp_send_cmd("CWD ", path, sock_control);
ftp_get_reply(sock_control);
}
}
//delete
void del(char *usr_cmd)
{
char *cmd = strchr(usr_cmd,' ');
char filename[1024];
if(cmd == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd == ' ')
cmd++;
}
if(cmd == NULL||cmd =='\0')
{
printf("command error!\n");
return;
}
else
{
strncpy(filename,cmd,strlen(cmd));
filename[strlen(cmd)]='\0';
ftp_send_cmd("DELE",filename,sock_control);
ftp_get_reply(sock_control);
}
}
//mkdir
void mkdir_srv(char *usr_cmd)
{
char *cmd = strchr(usr_cmd,' ');
char path[1024];
if(cmd == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd == ' ')
cmd ++;
}
if(cmd == NULL||cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
strncpy(path,cmd,strlen(cmd));
path[strlen(cmd)]='\0';
ftp_send_cmd("MKD",path,sock_control);
ftp_get_reply(sock_control);
}
}
//rmdir
void rmdir_srv(char *usr_cmd)
{
char *cmd = strchr(usr_cmd,' ');
char path[1024];
if(cmd == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd == ' ')
cmd++;
}
if(cmd == NULL||cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
strncpy(path,cmd,strlen(cmd));
path[strlen(cmd)]='\0';
ftp_send_cmd("RMD",path,sock_control);
ftp_get_reply(sock_control);
}
}

//list files and directories in local host
void local_list()
{
DIR * dp;
struct dirent *dirp;
if((dp = opendir("./")) == NULL)
{
printf("opendir() error!\n");
return;
}
printf("Local file list:\n");
while((dirp = readdir(dp)) != NULL)
{
if(strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
continue;
printf("%s\n", dirp->d_name);
}
}

//print local current directory
void local_pwd()
{
char curr_dir[512];
int size = sizeof(curr_dir);
if(getcwd(curr_dir, size) == NULL)
printf("getcwd failed\n");
else
printf("Current local directory: %s\n", curr_dir);
}

//change local directory
void local_cd(char * usr_cmd)
{
char *cmd = strchr(usr_cmd, ' ');
char path[1024];
if(cmd == NULL)
{
printf("command error!\n");
return;
}
else
{
while(*cmd == ' ')
cmd ++;
}
if(cmd == NULL || cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
strncpy(path, cmd, strlen(cmd));
path[strlen(cmd)]='\0';
if(chdir(path) < 0)
printf("Local: chdir to %s error!\n", path);
else
printf("Local: chdir to %s\n", path);
}
}

void show_help()
{
printf("\033[32mhelp\033[0m\t--print this command list\n");
//
printf("\033[32mopen\033[0m\t--open the server\n");
printf("\033[32mclose\033[0m\t--close the connection with the server\n");
printf("\033[32mmkdir\033[0m\t--make new dir on the ftp server\n");
printf("\033[32mrmdir\033[0m\t--delete the dir on the ftp server\n");
printf("\033[32mdele\033[0m\t--delete the file on the ftp server\n");
//
printf("\033[32mpwd\033[0m\t--print the current directory of server\n");
printf("\033[32mls\033[0m\t--list the files and directoris in current directory of server\n");
printf("\033[32mcd [directory]\033[0m\n\t--enter of server\n");
printf("\033[32mmode\033[0m\n\t--change current mode, PORT or PASV\n");
printf("\033[32mput [local_file] \033[0m\n\t--send [local_file] to server as \n");
printf("\tif isn't given, it will be the same with [local_file] \n");
printf("\tif there is any \' \' in , write like this \'\\ \'\n");
printf("\033[32mget [remote file] \033[0m\n\t--get [remote file] to local host as\n");
printf("\tif isn't given, it will be the same with [remote_file] \n");
printf("\tif there is any \' \' in , write like this \'\\ \'\n");
printf("\033[32mlpwd\033[0m\t--print the current directory of local host\n");
printf("\033[32mlls\033[0m\t--list the files and directoris in current directory of local host\n");
printf("\033[32mlcd [directory]\033[0m\n\t--enter of localhost\n");
printf("\033[32mbye\033[0m\t--quit this ftp client program\n");
}

//get user and password for login
void get_user()
{
char read_buf[64];
printf("User(Press for anonymous): ");
fgets(read_buf, sizeof(read_buf), stdin);
if(read_buf[0]=='\n')
strncpy(user, "anonymous", 9);
else
strncpy(user, read_buf, strlen(read_buf)-1);
}
void get_pass()
{
char read_buf[64];
printf("Password(Press for anonymous): ");
echo_off();
fgets(read_buf, sizeof(read_buf), stdin);
if(read_buf[0]=='\n')
strncpy(passwd, "anonymous", 9);
else
strncpy(passwd, read_buf, strlen(read_buf)-1);
echo_on();
printf("\n");
}

//login to the server
int ftp_login()
{
int err;
get_user();
if(ftp_send_cmd("USER ", user, sock_control) < 0)
cmd_err_exit("Can not send message",1);
err = ftp_get_reply(sock_control);
if(err == 331)
{
get_pass();
if(ftp_send_cmd("PASS ", passwd, sock_control) <= 0)
cmd_err_exit("Can not send message",1);
else
err = ftp_get_reply(sock_control);
if(err == 230)
return 1;
else if(err == 531)
return 1;
else
{
printf("Password error!\n");
return 0;
}

}
else
{
printf("User error!\n");
return 0;
}
}

//deal with user's command
int ftp_usr_cmd(char * usr_cmd)
{
/
if(!strncmp(usr_cmd,"open",4))
return 15;
if(!strncmp(usr_cmd,"close",5))
return 16;
if(!strncmp(usr_cmd,"mkdir",5))
return 17;
if(!strncmp(usr_cmd,"rmdir",5))
return 18;
if(!strncmp(usr_cmd,"dele",4))
return 19;

if(!strncmp(usr_cmd,"ls",2))
return 1;
if(!strncmp(usr_cmd,"pwd",3))
return 2;
if(!strncmp(usr_cmd,"cd ",3))
return 3;
if(!strncmp(usr_cmd,"put ",4))
return 4;
if(!strncmp(usr_cmd,"get ",4))
return 5;
if(!strncmp(usr_cmd,"bye",3))
return 6;
if(!strncmp(usr_cmd,"mode",4))
return 7;
if(!strncmp(usr_cmd,"lls",3))
return 11;
if(!strncmp(usr_cmd,"lpwd",4))
return 12;
if(!strncmp(usr_cmd,"lcd ",4))
return 13;
return -1;
}
void open_srv()
{
char usr_cmd[1024];
int cmd_flag;
while(1)
{
printf("ftp_cli>");
fgets(usr_cmd,510,stdin);
fflush(stdin);
if(usr_cmd[0] == '\n')
continue;
usr_cmd[strlen(usr_cmd)-1] = '\0';
cmd_flag = ftp_usr_cmd(usr_cmd);
if(cmd_flag == 15)
{
char *cmd = strchr(usr_cmd,' ');
char dress_ftp[1024];
if(cmd == NULL)
{
printf("command error!\n");
show_help();
return;
}
else
{
while(*cmd == ' ')
cmd++;
}
if(cmd == NULL||cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
char * dr = "127.0.0.1";
strncpy(dress_ftp,cmd,strlen(cmd));
dress_ftp[strlen(cmd)] = '\0';
printf("%s",dress_ftp);
//if(dress_ftp == "127.0.0.1")
if(1)
{
printf("Connect Seccessed!\n");
start_ftp_cmd(dr,DEFAULT_FTP_PORT);
}
else
{
printf("Inviable Server Dress!\n");
}
}
}
else
{
switch(cmd_flag)
{
case 11:
local_list();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 12:
local_pwd();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 13:
local_cd(usr_cmd);
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 6://quit
printf("BYE TO WEILIQI FTP!\n");
exit(0);
break;
default:
printf("command error!\n");
show_help();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
}
}
}

}



int start_ftp_cmd(char * host_ip_addr, int port)
{
int err;
int cmd_flag;
char usr_cmd[1024];
err = fill_host_addr(host_ip_addr, &ftp_server, port);
if(err == 254)
cmd_err_exit("Invalid port!",254);
if(err == 253)
cmd_err_exit("Invalid server address!",253);

sock_control = xconnect(&ftp_server,1);
if((err = ftp_get_reply(sock_control)) != 220)
cmd_err_exit("Connect error!",220);
do
{
err = ftp_login();
}while(err != 1);

while(1)
{
printf("ftp_cli>");
fgets(usr_cmd, 510, stdin);
fflush(stdin);
if(usr_cmd[0] == '\n')
continue;
usr_cmd[strlen(usr_cmd)-1] = '\0';
cmd_flag = ftp_usr_cmd(usr_cmd);
switch(cmd_flag)
{
case 1:
ftp_list();
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
case 2:
ftp_pwd();
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
case 3:
ftp_cd(usr_cmd);
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
case 4:
ftp_put(usr_cmd);
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
case 5:
ftp_get(usr_cmd);
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
case 6:
ftp_quit();
printf("BYE TO WEILIQI FTP!\n");
exit(0);
case 7:
mode = (mode + 1)%2;
if(mode)
printf("change mode to PASV\n");
else
printf("change mode to PORT\n");
break;
case 11:
local_list();
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
case 12:
local_pwd();
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
case 13:
local_cd(usr_cmd);
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;

case 16:
close_cli();
memset(usr_cmd,'\0',sizeof(usr_cmd));
open_srv();
break;
case 17:
mkdir_srv(usr_cmd);
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 18:
rmdir_srv(usr_cmd);
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 19:
del(usr_cmd);
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
default:
show_help();
memset(usr_cmd, '\0',sizeof(usr_cmd));
break;
}
}
return 1;
}
/
void open_ftpsrv()
{
char usr_cmd[1024];
int cmd_flag;
while(1)
{
printf("ftp_cli>");
fgets(usr_cmd,510,stdin);
fflush(stdin);
if(usr_cmd[0] == '\n')
continue;
usr_cmd[strlen(usr_cmd)-1] = '\0';
cmd_flag = ftp_usr_cmd(usr_cmd);
if(cmd_flag == 15)
{
char *cmd = strchr(usr_cmd,' ');
char dress_ftp[1024];
if(cmd == NULL)
{
printf("command error!\n");
show_help();
return;
}
else
{
while(*cmd == ' ')
cmd++;
}
if(cmd == NULL||cmd == '\0')
{
printf("command error!\n");
return;
}
else
{
char * dr = "127.0.0.1";
strncpy(dress_ftp,cmd,strlen(cmd));
dress_ftp[strlen(cmd)] = '\0';
printf("%s",dress_ftp);
//if(dress_ftp == "127.0.0.1")
if(1)
{
printf("Connect Seccessed!\n");
start_ftp_cmd(dr,DEFAULT_FTP_PORT);
}
else
{
printf("Inviable Server Dress!\n");
}
}
}
else
{
switch(cmd_flag)
{
case 11:
local_list();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 12:
local_pwd();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 13:
local_cd(usr_cmd);
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
case 6://quit
printf("BYE TO WEILIQI FTP!\n");
exit(0);
break;
default:
printf("command error!\n");
show_help();
memset(usr_cmd,'\0',sizeof(usr_cmd));
break;
}
}
}

}
//
//main process
int main(int argc, char * argv[])
{
if(argc == 1)
{
printf("Hello!Welcome to weiliqi FTP!\n");
open_ftpsrv();

}
else
{
if(argc == 2 && argc == 3)
{
if(argv[2]==NULL)
start_ftp_cmd(argv[1], DEFAULT_FTP_PORT);
else
start_ftp_cmd(argv[1], atol(argv[2]));
}
else
{
printf("INPUT INVIABLE!\n");
exit(-1);
}
}
return 1;
}

 

 运行结果:

root@zhangkaiqiang-desktop:/home/salman/DealAudio/ftp_wlq/ftp_wlq/ftp_wlq/FTP# ./ftp_cli
Hello!Welcome to weiliqi FTP!
ftp_cli>open 192.168.1.194
192.168.1.194Connect Seccessed!
220 (vsFTPd 3.0.3)
User(Press  for anonymous): zhangkaiqiang
331 Please specify the password.
Password(Press  for anonymous):
230 Login successful.
ftp_cli>
 

举报

相关推荐

0 条评论