#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<pwd.h>
#include<signal.h>
#include<time.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<termios.h>
#include"ftp.h"
FTPCMD ftp_cmd[]=
{
<span style="white-space:pre"> </span>{"dir","LIST",NULL,NULL}, //列表文件目录(数据连接命令,分主动和被动模式)
<span style="white-space:pre"> </span>{"ls","LIST",NULL,NULL}, //列表文件目录(数据连接命令,分主动和被动模式)
<span style="white-space:pre"> </span>{"get","RETR","Local file",NULL}, //从服务器下载文件(数据连接命令,分主动和被动模式)
<span style="white-space:pre"> </span>{"put","STOR","Local file",NULL}, //向服务器上传文件(数据连接命令,分主动和被动模式)
<span style="white-space:pre"> </span>{"cd","CWD","Remote directory",do_common_cmd}, //改变当前服务器的文件目录
<span style="white-space:pre"> </span>{"delete","DELE","Remote file",do_common_cmd}, //删除文件
<span style="white-space:pre"> </span>{"lcd","LCD",NULL,do_lchdir}, //显示或设定当前客户端的工作目录(本地命令)
<span style="white-space:pre"> </span>{"mkdir","MKD","Remote directory",do_common_cmd}, //创建目录
<span style="white-space:pre"> </span>{"rkdir","RKD","Remote directory",do_common_cmd}, //删除目录
<span style="white-space:pre"> </span>{"passive","passive",NULL,do_pasv}, //客户端主动被动模式切换(本地命令)
<span style="white-space:pre"> </span>{"pwd","PWD",NULL,do_common_cmd}, //显示服务器当前工作目录
<span style="white-space:pre"> </span>{"binary","TYPE I",NULL,do_common_cmd}, //设置传输文件的类型为文本
<span style="white-space:pre"> </span>{"ascii","TYPE A",NULL,do_common_cmd}, //设置传输文件的类型为二进制
<span style="white-space:pre"> </span>{"bye","QUIT",NULL,do_common_cmd}, //退出登录
<span style="white-space:pre"> </span>{"user","USER","Username",do_user} //登录FTP用户名
};
//定义一个FTPCMD结构体类型的数组,前四行的四个命令的处理函数由于有主动和被动两种模式,所以其初始化将在init函数中
#define CMD_NUM sizeof(ftp_cmd)/sizeof(ftp_cmd[0]) //命令个数
int mode;<span style="white-space:pre"> </span> //连接模式,主动或被动
int sockfd_cmd;<span style="white-space:pre"> </span>//控制连接套接字
volatile sig_atomic_t ctrl_z;<span style="white-space:pre"> </span>
int found;<span style="white-space:pre"> </span> //为1,输入的命令合法
int data_flag;<span style="white-space:pre"> </span>//为1,启动了数据连接
char args[ARGSIZE];<span style="white-space:pre"> </span>//ftp命令参数
char ip_args[ARGSIZE];<span style="white-space:pre"> </span>//port命令字串,如192.168.1.137
int ipstr_len; //ip字符串长度
struct sockaddr_in local_addr;<span style="white-space:pre"> </span>//客户端本地套接字
struct sockaddr_in server_addr;<span style="white-space:pre"> </span>//ftp服务器套接字
char cmd_str[CMDSIZE];<span style="white-space:pre"> </span>//输入的ftp命令字符串
char cmd[CMDSIZE];<span style="white-space:pre"> </span>//ftp协议命令字
int main(int argc,char *argv[])
{
<span style="white-space:pre"> </span>struct hostent *host;
<span style="white-space:pre"> </span>int found;
<span style="white-space:pre"> </span>int port=21;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(argc<2)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Usage: %s hostname portnumber\a\n",argv[0]);
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if((host=gethostbyname(argv[1]))==NULL)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Usage: %s hostname portnumber\a\n",argv[0]);
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//创建客户端控制连接套接字
<span style="white-space:pre"> </span>if((sockfd_cmd=socket(PF_INET,SOCK_STREAM,0))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Socket Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>init();<span style="white-space:pre"> </span> //初始化
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>login(host,port);<span style="white-space:pre"> </span>//登录ftp server
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//生成port命令的ip字符串部分
<span style="white-space:pre"> </span>ipstr_len=make_port_args(sockfd_cmd,&local_addr);
<span style="white-space:pre"> </span>//此函数将客户端IP预先构造为PORT命令中IP字符串的形式(例如"192,168,1,137,"),存放于全局变量ip_args中
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>int size =sizeof(cmd);<span style="white-space:pre"> </span>//取ftp协议命令字大小
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//主循环
<span style="white-space:pre"> </span>for(;;)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("ftp> ");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!input_cmd(cmd_str,size)) //输入命令
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>continue;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>trim_right(cmd_str); //去除命令右边的空格
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>found=check_ftpcmd(cmd_str,cmd); //检查命令是否正确,并返回对应的命令在数组中的位置
<span style="white-space:pre"> </span>if(found<0);
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("Invalid command.\n");
<span style="white-space:pre"> </span>continue;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(ftp_cmd[found].args) //如果该命令有参数
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if(!having_args(cmd)) //如果命令没有直接带有参数
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("%s ",ftp_cmd[found].args); //显示该命令应有参数
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>input_cmd(args,size); //输入参数
<span style="white-space:pre"> </span>trim_right(args); //去除右边的空格
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>ftp_cmd[found].handler(sockfd_cmd,cmd,args); //执行该ftp命令
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return 0;
}
void init()
{
<span style="white-space:pre"> </span>mode=PASSIVE_ON;<span style="white-space:pre"> </span>//设置默认为被动模式
<span style="white-space:pre"> </span>ctrl_z=0;<span style="white-space:pre"> </span>//ctrl+z按下标志复原
<span style="white-space:pre"> </span>data_flag=0;<span style="white-space:pre"> </span>//数据连接建立标志复原
<span style="white-space:pre"> </span>memset(args,0,sizeof(args));<span style="white-space:pre"> </span>//将ftp命令参数初始化为0
<span style="white-space:pre"> </span>ftp_cmd[0].handler=do_list_pasv;
<span style="white-space:pre"> </span>ftp_cmd[1].handler=do_list_pasv;
<span style="white-space:pre"> </span>ftp_cmd[2].handler=do_get_pasv;
<span style="white-space:pre"> </span>ftp_cmd[3].handler=do_put_pasv;
<span style="white-space:pre"> </span>//为ftp_cmd数组的前4个命令的处理函数赋值,设为被动模式的函数
<span style="white-space:pre"> </span>ignore_sigtstp();<span style="white-space:pre"> </span>//忽略SIGTSTP信号
}
//此函数的主要功能就是设置FTP数据命令默认为被动模式,并且忽略了SIGTSTP信号,
//因为程序要利用来中止正在进行ctrl+z发出SIGTSTP信号来中止正在进行的数据传输命令
void login(struct hostent *host,int portnumber)
{
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status;<span style="white-space:pre"> </span>//服务器状态应答码
<span style="white-space:pre"> </span>int fin=0;
<span style="white-space:pre"> </span>//对ftp服务器套接字地址赋值
<span style="white-space:pre"> </span>memset(&server_addr,0,sizeof(server_addr));
<span style="white-space:pre"> </span>server_addr.sin_family=AF_INET;
<span style="white-space:pre"> </span>server_addr.sin_port=htons(portnumber);
<span style="white-space:pre"> </span>server_addr.sin_addr=*((struct in_addr*)host->h_addr);
<span style="white-space:pre"> </span>//连接到ftp服务器
<span style="white-space:pre"> </span>if(connect(sockfd_cmd,(struct sockaddr*)(&server_addr),sizeof(server_addr))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Connect Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>get_ftpcmd_status(sockfd_cmd,res_buffer);
<span style="white-space:pre"> </span>printf("Name(%s:%s): ",inet_ntoa(server_addr.sin_addr),get_username());
<span style="white-space:pre"> </span>//输入用户名
<span style="white-space:pre"> </span>fgets(cmd,sizeof(cmd),stdin);
<span style="white-space:pre"> </span>cmd[strlen(cmd)-1]=0;
<span style="white-space:pre"> </span>send_ftpcmd(sockfd_cmd,"USER",cmd);
<span style="white-space:pre"> </span>status=get_ftpcmd_status(sockfd_cmd,res_buffer);
<span style="white-space:pre"> </span>//输入密码
<span style="white-space:pre"> </span>printf("Password: ");
<span style="white-space:pre"> </span>terminal_echo_off(STDIN_FILENO); //隐藏输入显示
<span style="white-space:pre"> </span>fgets(cmd,sizeof(cmd),stdin); //接受标准输入sizeof(cmd)字节到cmd
<span style="white-space:pre"> </span>terminal_echo_on(STDOUT_FILENO); //显示输入显示
<span style="white-space:pre"> </span>printf("\n");
<span style="white-space:pre"> </span>cmd[strlen(cmd)-1]=0;
<span style="white-space:pre"> </span>send_ftpcmd(sockfd_cmd,"PASS",cmd); //发送PASS协议给ftp服务器
<span style="white-space:pre"> </span>status=get_ftpcmd_status(sockfd_cmd,res_buffer); //取得返回状态码
}
<span style="white-space:pre"> </span>
int make_port_args(int fd,struct sockaddr_in *local_addr)
{
<span style="white-space:pre"> </span>char *ipstr; //ip字符串
<span style="white-space:pre"> </span>int len; //长度
<span style="white-space:pre"> </span>memset(ip_args,0,ARGSIZE); //初始化
<span style="white-space:pre"> </span>ipstr=get_localip(fd,local_addr); //获得本机IP
<span style="white-space:pre"> </span>replace_delim(ipstr,'.',','); //将'.'替换为','
<span style="white-space:pre"> </span>len=strlen(ipstr);
<span style="white-space:pre"> </span>
strncpy(ip_args,ipstr,strlen(ipstr)); //将ip地址字符串复制到ip_args
<span style="white-space:pre"> </span>strcat(ip_args,","); //结尾加上','
<span style="white-space:pre"> </span>return len+1;
}
int send_ftpcmd(int fd,const char *cmd,const char *args)
{
<span style="white-space:pre"> </span>char buf[128]; //发送缓冲区
<span style="white-space:pre"> </span>int z; //储存write()返回值
<span style="white-space:pre"> </span>memset(buf,0,sizeof(buf)); //sizeof是计算buf数组编译时所分配的数组空间的大小,所以的这里是将整个数组清零初始化
<span style="white-space:pre"> </span>strncpy(buf,cmd,strlen(cmd)); //strlen时计算从cmd字符指针开始直到碰到第一个字符串结束符'\0'为止的长度值,所以这里只是将cmd命令复制给buf前命令长度的字符
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(args) //如果有参数
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>strcat(buf," "); //buf字符串后加入空格“ ”
<span style="white-space:pre"> </span>strcat(buf,args); //buf字符串后加入参数
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>strcat(buf,"\r\n"); //buf字符串后加入回车
<span style="white-space:pre"> </span>z=write(fd,buf,strlen(buf)); //通过fd发送buf字符串有内容的前strlen(buf)字节
<span style="white-space:pre"> </span>if(z==-1) //错误
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>bail("write");
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return z; //返回发送的字节数
}
int input_cmd(char *cmd,int size) //输入命令函数
{
<span style="white-space:pre"> </span>int len; //命令长度
<span style="white-space:pre"> </span>memset(cmd,0,size); //cmd初始化清零
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>fgets(cmd,size,stdin); //输入命令--从标准输入流stdin读入size字节的数据到cmd
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>len=strlen(cmd); //计算cmd内容长度
<span style="white-space:pre"> </span>if(len) //如果长度不为0
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>cmd[len-1]=0; //去掉末尾的‘\n'
<span style="white-space:pre"> </span>len--;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return len; //返回长度
}
char *trim_right(char *cmd_str) //该函数用于去掉命令字符串中右边的空格
{
<span style="white-space:pre"> </span>int i,len;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>len=strlen(cmd_str);
<span style="white-space:pre"> </span>i=1;
<span style="white-space:pre"> </span>while(*(cmd_str+len-i)==32) //从最后一个字符开始,如果该字符为空格
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>*(cmd_str+len-i)=0; //将该字符复制为0
<span style="white-space:pre"> </span>i++; //i++,使下次循环处理前一个字符的情况
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return cmd_str;
}
/*
根据输入的FTP命令字符串cmd_str,在ftp_cmd[i]中搜索是否存在此输入的FTP命令,若找到则将此命令字符串复制到全局变量cmd中
cmd_str,输入的FTP命令字符串
cmd,对应的标准FTP协议命令字
*/
int check_ftpcmd(char *cmd_str,char *cmd)
{
<span style="white-space:pre"> </span>int found,i,j;
<span style="white-space:pre"> </span>int withargs=0;
<span style="white-space:pre"> </span>char *p=NULL;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>i=j=0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//清空用于储存FTP命令缓存字符数组cmd
<span style="white-space:pre"> </span>memset(cmd,0,CMDSIZE);
<span style="white-space:pre"> </span>memset(args,0,CMDSIZE);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//去掉命令字符串中左边的空格
<span style="white-space:pre"> </span>while(*(cmd_str+j)==32)
<span style="white-space:pre"> </span>j++;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//若未携带参数,则直接使用cmd_str,否则去掉参数部分
<span style="white-space:pre"> </span>if(!strstr(cmd_str+j," ")) //未携带参数
<span style="white-space:pre"> </span>p=cmd_str+j; //p指向命令起始地址
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>p=strtok(cmd_str+j," "); //获得第一个参数前的命令字符串
<span style="white-space:pre"> </span>withargs=1; //有参数
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//遍历检查是否匹配输入的命令字符串
<span style="white-space:pre"> </span>while(i<CMD_NUM)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if(!strcmp(p,ftp_cmd[i].alias)) //若p与ftp_cmd[i].alias相等
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>found=i; //found记录下命令序数
<span style="white-space:pre"> </span>break; //跳出循环
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>i++; //否则继续循环查找
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(i==CMD_NUM) //没有找到匹配该输入字符串的FTP命令
<span style="white-space:pre"> </span>found=-1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>else //即找到了匹配的字符串
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>strncpy(cmd,ftp_cmd[i].name,strlen(ftp_cmd[i].name));
<span style="white-space:pre"> </span>//将相应的FTP协议命令复制到cmd字符串中
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(withargs)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>//获得cmd_str中剩下肯呢个有的命令参数
<span style="white-space:pre"> </span>while(p=strtok(NULL," "))
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>strcat(cmd," ");
<span style="white-space:pre"> </span>strcat(cmd,p);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return found;
}
/*
判断当前需要进行数据传输的FTP名啦是否携带了必要的参数
返回0,为携带必要的参数;返回1,携带了必要的参数
*/
int having_args(char *cmd)
{
<span style="white-space:pre"> </span>char *p=NULL;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>memset(args,0,sizeof(args)); //FTP命令参数全局变量args初始化清零
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!(p=strstr(cmd," "))) //如果没有空格即没有参数
<span style="white-space:pre"> </span>return 0; //返回
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>*p++=0; //将全局变量cmd中的空格位置设为0
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>strncpy(args,p,strlen(p)); //将参数复制到全局变量args中
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 1;
}
/*
用指定字符替换字符串中的某个特定字符
ipstr,在其中替换的字符串
orig,被替换的字符
substitute,用于替换的字符
*/
void replace_delim(char *ipstr,char orig,char substitute)
{
<span style="white-space:pre"> </span>char *temp;
<span style="white-space:pre"> </span>temp=ipstr;
<span style="white-space:pre"> </span>while(*temp!=0)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if(*temp==orig)
<span style="white-space:pre"> </span>*temp=substitute;
<span style="white-space:pre"> </span>temp++;
<span style="white-space:pre"> </span>}
}
int get_ftpcmd_status(int sockfd,char *res_buffer)
{
<span style="white-space:pre"> </span>char code[5],*msg;
<span style="white-space:pre"> </span>int z,status;
<span style="white-space:pre"> </span>do
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>memset(res_buffer,0,BUFSIZE); //接受缓存初始化
redo:
<span style="white-space:pre"> </span>z=read(sockfd,res_buffer,BUFSIZE); //接受数据
<span style="white-space:pre"> </span>if(z<0&&errno==EINTR) //如果没有接受到
<span style="white-space:pre"> </span>goto redo; //继续重新接受
<span style="white-space:pre"> </span>msg=strtok(res_buffer,"\r\n"); //将接受到的数据按回车为分隔符分解字符串
<span style="white-space:pre"> </span>printf("%s\n",msg); //打印出分解出的第一个字符串
<span style="white-space:pre"> </span>memset(code,0,sizeof(code)); //储存应答代码的字符串清零
<span style="white-space:pre"> </span>status=atoi(strncpy(code,msg,4));
<span style="white-space:pre"> </span>//将msg的前4个字符赋予code字符串,然后转化为整形赋值给status
<span style="white-space:pre"> </span>if(code[3]!=' '||status<=0)
<span style="white-space:pre"> </span>status=-1;
<span style="white-space:pre"> </span>if(status==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>while(msg=strtok(NULL,"\r\n")) //如果以回车分解出的字符串不为空,则继续分解字符串
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("%s\n",msg); //打印出分解出的字符串的第一段
<span style="white-space:pre"> </span>memset(code,0,sizeof(code)); //初始化code
<span style="white-space:pre"> </span>status=atoi(strncpy(code,msg,4)); //status赋值
<span style="white-space:pre"> </span>if(code[3]!=' ') //
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>status=-1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if(status>0) //直到status>0
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>break; //跳出循环
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}while(1);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return status; //返回状态码
}
int do_user(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status,fin=0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args);
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status!=331)
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>printf("Password:");
<span style="white-space:pre"> </span>terminal_echo_off(STDIN_FILENO);
<span style="white-space:pre"> </span>fgets(cmd,CMDSIZE,stdin);
<span style="white-space:pre"> </span>terminal_echo_on(STDOUT_FILENO);
<span style="white-space:pre"> </span>printf("\n");
<span style="white-space:pre"> </span>cmd[strlen(cmd)-1]=0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(sockfd_cmd,"PASS",cmd);
<span style="white-space:pre"> </span>get_ftpcmd_status(sockfd_cmd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
}
int do_common_cmd(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status,fin=0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(strlen(args))
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args);
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,NULL);
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status==250||status==257||status==200||status==230||status==331)
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status==221||status==421) //quit命令成功响应
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>close(fd);
<span style="white-space:pre"> </span>exit(0);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return -1;
}
int do_pasv(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>mode=!mode; //切换主动和被动模式
<span style="white-space:pre"> </span>if(mode)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("Passive mode on.\n");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ftp_cmd[0].handler=do_list_pasv;
<span style="white-space:pre"> </span>ftp_cmd[1].handler=do_list_pasv;
<span style="white-space:pre"> </span>ftp_cmd[2].handler=do_get_pasv;
<span style="white-space:pre"> </span>ftp_cmd[3].handler=do_put_pasv;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("Passive mode off.\n");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ftp_cmd[0].handler=do_list_active;
<span style="white-space:pre"> </span>ftp_cmd[1].handler=do_list_active;
<span style="white-space:pre"> </span>ftp_cmd[2].handler=do_get_active;
<span style="white-space:pre"> </span>ftp_cmd[3].handler=do_put_active;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return mode;
}
//显示或设定当前客户端的工作目录
int do_lchdir(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>char *cd;
<span style="white-space:pre"> </span>char buf[256];
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>memset(buf,0,sizeof(buf));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>strtok(cmd," ");
<span style="white-space:pre"> </span>cd=strtok(NULL,cmd);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!cd)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>getcwd(buf,sizeof(buf));
<span style="white-space:pre"> </span>printf("Local directory now%s\n",buf);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if((chdir(cd))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>bail("Change dir");
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>printf("Local directory now %s\n",cd);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
}
//获得用于当前数据传输所使用的socket正在监听的端口
//返回port,站在监听的port
int get_active_port(int fd_listen)
{
<span style="white-space:pre"> </span>unsigned short port; //端口值
<span style="white-space:pre"> </span>socklen_t sin_size; //整形变量sin_size用于储存地址结构体大小
<span style="white-space:pre"> </span>sin_size=sizeof(struct sockaddr_in); //赋值
<span style="white-space:pre"> </span>getsockname(fd_listen,(struct sockaddr*)&local_addr,&sin_size);
<span style="white-space:pre"> </span>//取得坚挺套接字fd_listen的地址存入local_addr
<span style="white-space:pre"> </span>port=ntohs(local_addr.sin_port);
<span style="white-space:pre"> </span>//取得地址中的端口值并将网络字节序转换为主机字节序赋值给port
<span style="white-space:pre"> </span>return port; //返回port
}
//获得当前发出FTP命令客户端的IP
char * get_localip(int fd,struct sockaddr_in *local_addr)
{
<span style="white-space:pre"> </span>int size=sizeof(struct sockaddr_in); //地址结构体长度
<span style="white-space:pre"> </span>getsockname(fd,(struct sockaddr*)local_addr,&size); //取得地址
<span style="white-space:pre"> </span>return inet_ntoa(local_addr->sin_addr);
<span style="white-space:pre"> </span>//取得地址中的ip地址值并转换为互联网标准的点分格式的字符串并返回
}
//函数get_active_port和get_localip通过调用ggetsockname,获得当前客户端监听套接字fd_listen所关联的ip地址和监听端口。
/*
用于主动模式下向FTP服务器发送port命令
返回0,表示port命令发送失败;
返回sockfd_listen_act,表示port命令发送成功
*/
int active_notify(int fd)
{
<span style="white-space:pre"> </span>int status,fin=0;
<span style="white-space:pre"> </span>int sockfd_listen_act;
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>unsigned short port;
<span style="white-space:pre"> </span>char quot[4],resi[4];
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//清除ip_args中前次PORT命令中和端口相关的数据
<span style="white-space:pre"> </span>memset(ip_args+ipstr_len,0,ARGSIZE-ipstr_len);
<span style="white-space:pre"> </span>//ip_args这里是字符指针,ip_args+ipstr_len即ip_args字符串中ip地址结束的位置,即port数据开始的位置,从次位置开始见后面的ARGSIZE-ipstr_len位清零初始化
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//获得客户端用于被动模式的监听套接字
<span style="white-space:pre"> </span>sockfd_listen_act=active_listen();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(sockfd_listen_act==-1) // 监听套接字创建失败
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>//获得监听端口
<span style="white-space:pre"> </span>port=get_active_port(sockfd_listen_act);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>snprintf(quot,sizeof(quot),"%d",port/256); //相比sprintf多了第二个参数,即复制的位数
<span style="white-space:pre"> </span>snprintf(resi,sizeof(resi),"%d",port%256);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//给ip_args添加上port参数
<span style="white-space:pre"> </span>strcat(ip_args,quot);
<span style="white-space:pre"> </span>strcat(ip_args,",");
<span style="white-space:pre"> </span>strcat(ip_args,resi);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(fd,"port",ip_args); //发送port命令
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer); //获取服务器应答代码
<span style="white-space:pre"> </span>if(status!=200) //如果端口命令不成功
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return sockfd_listen_act;
}
/*
创建用于主动模式下进行数据传输的本地socket,并在此socket上进行监听
返回-1,失败;返回sockfd,成功
*/
int active_listen()
{
<span style="white-space:pre"> </span>int sockfd;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//创建数据连接套接字
<span style="white-space:pre"> </span>if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Socket Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//设置监听套接字地址
<span style="white-space:pre"> </span>memset(&local_addr,0,sizeof(local_addr));
<span style="white-space:pre"> </span>local_addr.sin_family=AF_INET;
<span style="white-space:pre"> </span>local_addr.sin_port=0;
<span style="white-space:pre"> </span>local_addr.sin_addr.s_addr=htonl(INADDR_ANY);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(bind(sockfd,(struct sockaddr*)(&local_addr),sizeof(local_addr))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Bind Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(listen(sockfd,5))
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Listen Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return sockfd;
}
/*
用于被动模式下向FTP发送PASV命令
返回port_pasv,表示正确收到服务器发挥的PORT命令
返回0,表示PORT命令接受失败
*/
int passive_notify(int fd)
{
<span style="white-space:pre"> </span>int status,fin=0;
<span style="white-space:pre"> </span>int port_pasv;
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(fd,"PASV",NULL);
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>if(status!=27) //弱国PASV命令不成功
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>port_pasv=parse_port(res_buffer,strlen(res_buffer));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return port_pasv;
}
int parse_port(char *s,int len)
{
<span style="white-space:pre"> </span>char *p;
<span style="white-space:pre"> </span>char *parm[6]; //用于储存服务器返回的字符串的6个分段
<span style="white-space:pre"> </span>int port,resi,quot;
<span style="white-space:pre"> </span>int i=0;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>memset(s+len-1,0,1); //最后一个字节清零
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>p=strstr(s,"("); //查找第一个“(”
<span style="white-space:pre"> </span>p++;
<span style="white-space:pre"> </span>parm[i++]=strtok(p,","); //将字符串以“,"分段,并将第一个分段存入parm[0]
<span style="white-space:pre"> </span>while(parm[i++]=strtok(NULL,",")); //依次将字符串的后几个分段存入parm数组
<span style="white-space:pre"> </span>resi=atoi(parm[5]); //取port参数
<span style="white-space:pre"> </span>quot=atoi(parm[4]);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>port=quot*256+resi; //计算port值
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return port; //返回port值
}
int make_conn_active(int fd_listen)
{
<span style="white-space:pre"> </span>int sockfd;
<span style="white-space:pre"> </span>socklen_t sin_size;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//等待FTP服务器连接过来
<span style="white-space:pre"> </span>if((sockfd=accept(fd_listen,(struct sockaddr*)(&local_addr),&sin_size))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Accept Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return sockfd;
}
int make_conn_passive(int port)
{
<span style="white-space:pre"> </span>int sockfd;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Socket Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>server_addr.sin_port=htons(port);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(connect(sockfd,(struct sockaddr*)(&server_addr),sizeof(server_addr))==-1)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fprintf(stderr,"Connect Error: %s\a\n",strerror(errno));
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return sockfd;
}
int list_files(int sockfd)
{
<span style="white-space:pre"> </span>unsigned char data[BUFSIZE];
<span style="white-space:pre"> </span>int z;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//允许对Ctrl+z信号进行处理
<span style="white-space:pre"> </span>unignore_sigtstp();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>for(;;)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>memset(data,0,sizeof(data));
redo:
<span style="white-space:pre"> </span>if(z<0&&!ctrl_z&&errno==EINTR)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>bail("read()");
<span style="white-space:pre"> </span>goto redo;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if(ctrl_z) //输入了Ctrl+z
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>ctrl_z=0; //清除ctrl+z标志
<span style="white-space:pre"> </span>ignore_sigtstp(); //不允许对Ctrl+z信号进行处理
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//FTP服务器关闭数据连接
<span style="white-space:pre"> </span>if(z==0)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if(ctrl_z) //已经调用了ctrl+z信号处理函数
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>ctrl_z=0;
<span style="white-space:pre"> </span>ignore_sigtstp();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>printf("%s",data);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ignore_sigtstp();
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>return 1;
}
int download_file(char *filename,int sockfd)
{
<span style="white-space:pre"> </span>FILE *fp=NULL;
<span style="white-space:pre"> </span>unsigned char data[BUFSIZE];
<span style="white-space:pre"> </span>int z,file_size=0;
<span style="white-space:pre"> </span>char cur_dir[256];
<span style="white-space:pre"> </span>char filepath[256];
<span style="white-space:pre"> </span>const char *p;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>memset(filepath,0,sizeof(filepath));
<span style="white-space:pre"> </span>memcpy(filepath,"./",strlen("./"));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//获得文件路径中最后的文件名
<span style="white-space:pre"> </span>p=filename+strlen(filename);
<span style="white-space:pre"> </span>while(*p!='/'&&p!=filename)
<span style="white-space:pre"> </span>p--;
<span style="white-space:pre"> </span>if(p!=filename) //文件命中包饭路径
<span style="white-space:pre"> </span>p++;
<span style="white-space:pre"> </span>else //文件名中不包含路径
<span style="white-space:pre"> </span>p=filename;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!fp)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>strcat(filepath,p);
<span style="white-space:pre"> </span>fp=fopen(filepath,"a");
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//开始静茹数据传输阶段
<span style="white-space:pre"> </span>unignore_sigtstp();
<span style="white-space:pre"> </span>for(;;)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>memset(data,0,sizeof(data));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//每次读取BUFSIZE字节
<span style="white-space:pre"> </span>z=read(sockfd,data,sizeof(data));
<span style="white-space:pre"> </span>if(z<0&&!ctrl_z)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>bail("download_file");
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if(ctrl_z) //输入了Ctrl+z
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>ctrl_z=0; //清除ctrl+z标志
<span style="white-space:pre"> </span>fclose(fp);
<span style="white-space:pre"> </span>ignore_sigtstp(); //不允许对Ctrl+z信号进行处理
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//FTP服务器关闭数据连接
<span style="white-space:pre"> </span>if(z==0)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>fclose(fp);
<span style="white-space:pre"> </span>ignore_sigtstp();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(ctrl_z) //已经调用了ctrl+z信号处理函数
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>ctrl_z=0;
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>file_size+=z;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(fp)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>fwrite(data,z,1,fp);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>ignore_sigtstp();
<span style="white-space:pre"> </span>return file_size;
<span style="white-space:pre"> </span>}
}
int upload_file(FILE *fp,int sockfd)
{
<span style="white-space:pre"> </span>unsigned char data[BUFSIZE];
<span style="white-space:pre"> </span>int zr,zw;<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>int file_size=0 ;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>unignore_sigtstp();
<span style="white-space:pre"> </span>for(;;)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>memset(data,0,sizeof(data));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//每次读取BUFSIZE字节
<span style="white-space:pre"> </span>zr=fread(data,1,sizeof(data),fp);
<span style="white-space:pre"> </span>if(zr<0&&!ctrl_z)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>bail("read()");
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if(ctrl_z) //输入了Ctrl+z
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>ctrl_z=0; //清除ctrl+z标志
<span style="white-space:pre"> </span>fclose(fp);
<span style="white-space:pre"> </span>ignore_sigtstp(); //不允许对Ctrl+z信号进行处理
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//FTP服务器关闭数据连接
<span style="white-space:pre"> </span>if(zr==0)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>fclose(fp);
<span style="white-space:pre"> </span>ignore_sigtstp();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(ctrl_z) //已经调用了ctrl+z信号处理函数
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>ctrl_z=0;
<span style="white-space:pre"> </span>return 0;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>zw=write(sockfd,data,zr);
<span style="white-space:pre"> </span>if(zw<0&&!ctrl_z)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>bail("write()");
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>file_size+=zw;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ignore_sigtstp();
<span style="white-space:pre"> </span>return file_size;
}
void report(struct timeval *start_time,struct timeval *finish_time,int fsize)
{
<span style="white-space:pre"> </span>double dtime;
<span style="white-space:pre"> </span>char outstr[8],*p;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>memset(outstr,0,sizeof(outstr));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>dtime=(finish_time->tv_sec-start_time->tv_sec)+(finish_time->tv_usec-start_time->tv_usec)/(1000*1000.0);
<span style="white-space:pre"> </span>sprintf(outstr,"%-6.2f",dtime);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>p=strtok(outstr," ");
<span style="white-space:pre"> </span>if(p)
<span style="white-space:pre"> </span>printf("%d bytes receive in %s secs.\n",fsize,p);
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>printf("%d bytes receive in %-6.2f secs.\n",fsize,outstr);
}
int do_list_active(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status;
<span style="white-space:pre"> </span>int sockfd_act_listen; //主动模式下客户端监听套接字
<span style="white-space:pre"> </span>int sockfd_act; //主动模式下客户端数据传输套接字
<span style="white-space:pre"> </span>int ret;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=1; //开始进行数据连接状态
<span style="white-space:pre"> </span>sockfd_act_listen=active_notify(fd); //向FTP服务器发送PORT命令
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!sockfd_act_listen) //port命令失败
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args); //发送LIST命令给FTP服务器
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status/100==5) //如果有错误发送
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sockfd_act=make_conn_active(sockfd_act_listen);
<span style="white-space:pre"> </span>if(sockfd_act==-1);
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ret=list_files(sockfd_act);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>close(sockfd_act);
<span style="white-space:pre"> </span>close(sockfd_act_listen);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!ret) //在list命令过程中,用户输入了CTRL+Z
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>status=print_final_msg(fd,res_buffer); //准备接受FINAL_MSG并输出
out:
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>return 0;
}
int do_list_pasv(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>int port_pasv;
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status;
<span style="white-space:pre"> </span>int sockfd_pasv;
<span style="white-space:pre"> </span>int ret;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=1;
<span style="white-space:pre"> </span>port_pasv=passive_notify(fd); //向FTP服务器发送PORT命令
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!port_pasv) //port命令失败
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sockfd_pasv=make_conn_passive(port_pasv); //连接到FTP服务器
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!sockfd_pasv)
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args); //发送LIST命令给FTP服务器
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status/100==5) //如果有错误发送
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ret=list_files(sockfd_pasv);
<span style="white-space:pre"> </span>close(sockfd_pasv);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!ret) //在list命令过程中,用户输入了CTRL+Z
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>status=print_final_msg(fd,res_buffer); //准备接受FINAL_MSG并输出
out:
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>return 0;
}
int do_get_active(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status;
<span style="white-space:pre"> </span>int fz;
<span style="white-space:pre"> </span>int sockfd_act_listen; //主动模式下客户端监听套接字
<span style="white-space:pre"> </span>int sockfd_act; //主动模式下客户端数据传输套接字
<span style="white-space:pre"> </span>struct timeval start_time;
<span style="white-space:pre"> </span>struct timeval finish_time;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=1; //开始进行数据连接状态
<span style="white-space:pre"> </span>sockfd_act_listen=active_notify(fd); //向FTP服务器发送PORT命令
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!sockfd_act_listen) //port命令失败
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args); //发送GET命令给FTP服务器
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status/100==5) //文件下载失败
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sockfd_act=make_conn_active(sockfd_act_listen);
<span style="white-space:pre"> </span>if(sockfd_act==-1);
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>gettimeofday(&start_time,NULL);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>fz=download_file(args,sockfd_act);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>close(sockfd_act);
<span style="white-space:pre"> </span>close(sockfd_act_listen);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!fz) //在list命令过程中,用户输入了CTRL+Z
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>status=print_final_msg(fd,res_buffer); //准备接受FINAL_MSG并输出
out:
<span style="white-space:pre"> </span>gettimeofday(&finish_time,NULL);
<span style="white-space:pre"> </span>report(&start_time,&finish_time,fz);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>return 0;
}
int do_get_pasv(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>int port_pasv;
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status;
<span style="white-space:pre"> </span>int fz;
<span style="white-space:pre"> </span>int sockfd_pasv;
<span style="white-space:pre"> </span>struct timeval start_time;
<span style="white-space:pre"> </span>struct timeval finish_time;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=1;
<span style="white-space:pre"> </span>port_pasv=passive_notify(fd); //向FTP服务器发送PORT命令
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!port_pasv) //port命令失败
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sockfd_pasv=make_conn_passive(port_pasv); //连接到FTP服务器
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!sockfd_pasv)
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args); //发送LIST命令给FTP服务器
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status/100==5) //如果有错误发送
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>gettimeofday(&start_time,NULL);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>fz=download_file(args,sockfd_pasv);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>close(sockfd_pasv);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!fz) //在list命令过程中,用户输入了CTRL+Z
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>status=print_final_msg(fd,res_buffer); //准备接受FINAL_MSG并输出
out:
<span style="white-space:pre"> </span>gettimeofday(&finish_time,NULL);
<span style="white-space:pre"> </span>report(&start_time,&finish_time,fz);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>return 0;
}
int do_put_pasv(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>int port_pasv;
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status;
<span style="white-space:pre"> </span>int fz;
<span style="white-space:pre"> </span>int sockfd_pasv;
<span style="white-space:pre"> </span>struct timeval start_time;
<span style="white-space:pre"> </span>struct timeval finish_time;
<span style="white-space:pre"> </span>char cur_dir[256];
<span style="white-space:pre"> </span>FILE *fp;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>memset(cur_dir,0,sizeof(cur_dir));
<span style="white-space:pre"> </span>memcpy(cur_dir,"./",strlen("./"));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>strcat(cur_dir,args);
<span style="white-space:pre"> </span>if((fp=fopen(cur_dir,"r"))==NULL)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("file &s not exists\n",cur_dir);
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>port_pasv=passive_notify(fd); //向FTP服务器发送PORT命令
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!port_pasv) //port命令失败
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sockfd_pasv=make_conn_passive(port_pasv); //连接到FTP服务器
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!sockfd_pasv)
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args); //发送PUT命令给FTP服务器
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status/100==5) //如果有错误发送
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>gettimeofday(&start_time,NULL);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>fz=upload_file(fp,sockfd_pasv);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>close(sockfd_pasv);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!fz) //在list命令过程中,用户输入了CTRL+Z
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>status=print_final_msg(fd,res_buffer); //准备接受FINAL_MSG并输出
out:
<span style="white-space:pre"> </span>gettimeofday(&finish_time,NULL);
<span style="white-space:pre"> </span>report(&start_time,&finish_time,fz);
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>return 0;
}
int do_put_active(int fd,char *cmd,char *args)
{
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status;
<span style="white-space:pre"> </span>int fz;
<span style="white-space:pre"> </span>int sockfd_act_listen;
<span style="white-space:pre"> </span>int sockfd_act;
<span style="white-space:pre"> </span>struct timeval start_time;
<span style="white-space:pre"> </span>struct timeval finish_time;
<span style="white-space:pre"> </span>char cur_dir[256];
<span style="white-space:pre"> </span>FILE *fp;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>memset(cur_dir,0,sizeof(cur_dir));
<span style="white-space:pre"> </span>memcpy(cur_dir,"./",strlen("./"));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>strcat(cur_dir,args);
<span style="white-space:pre"> </span>if((fp=fopen(cur_dir,"r"))==NULL)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("file &s not exists\n",cur_dir);
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sockfd_act_listen=active_notify(fd); //向FTP服务器发送PORT命令
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!sockfd_act_listen) //port命令失败
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>send_ftpcmd(fd,cmd,args); //发送GET命令给FTP服务器
<span style="white-space:pre"> </span>status=get_ftpcmd_status(fd,res_buffer);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(status/100==5) //文件下载失败
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sockfd_act=make_conn_active(sockfd_act_listen);
<span style="white-space:pre"> </span>if(sockfd_act==-1);
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>gettimeofday(&start_time,NULL);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>fz=upload_file(fp,sockfd_act);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>close(sockfd_act);
<span style="white-space:pre"> </span>close(sockfd_act_listen);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(!fz) //在put命令过程中,用户输入了CTRL+Z
<span style="white-space:pre"> </span>return 1;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>status=print_final_msg(fd,res_buffer); //准备接受FINAL_MSG并输出
out:
<span style="white-space:pre"> </span>gettimeofday(&finish_time,NULL);
<span style="white-space:pre"> </span>report(&start_time,&finish_time,fz);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>data_flag=0;
<span style="white-space:pre"> </span>return 0;
}
int print_final_msg(int fd,char *res_buffer)
{
<span style="white-space:pre"> </span>char *msg,code[5];
<span style="white-space:pre"> </span>int status=1;
<span style="white-space:pre"> </span>while(msg=strtok(NULL,"\r\n"))
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("%s\n",msg);
<span style="white-space:pre"> </span>memset(code,0,sizeof(code));
<span style="white-space:pre"> </span>status=atoi(strncpy(code,msg,4));
<span style="white-space:pre"> </span>if(code[3]!=' ')
<span style="white-space:pre"> </span>status=1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if(status>0)
<span style="white-space:pre"> </span>return status;
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>return get_ftpcmd_status(fd,res_buffer);
}
char *get_username()
{
<span style="white-space:pre"> </span>struct passwd *ppasswd;
<span style="white-space:pre"> </span>ppasswd=getpwuid(getuid());
<span style="white-space:pre"> </span>return ppasswd->pw_name;
}
void ignore_sigtstp()
{
<span style="white-space:pre"> </span>struct sigaction abort_action; //声明信号处理结构体变量abort_action
<span style="white-space:pre"> </span>memset(&abort_action,0,sizeof(abort_action)); //初始化清零
<span style="white-space:pre"> </span>abort_action.sa_flags=0; //无特殊选项
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(sigaction(SIGTSTP,NULL,&abort_action)==-1)
<span style="white-space:pre"> </span>//取得SIGTSTP信号之前的信号处理结构体变量存入abort_action
<span style="white-space:pre"> </span>perror("Failed to get old handler for SIGTSTP");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>abort_action.sa_handler=SIG_IGN; //将信号处理函数设为忽略
<span style="white-space:pre"> </span>if(sigaction(SIGTSTP,&abort_action,NULL)==-1) //对SIGTSTP处理相关进行新的设置
<span style="white-space:pre"> </span>perror("Failed to ignore SIGTSTP");
}
void unignore_sigtstp()
{
<span style="white-space:pre"> </span>struct sigaction abort_action;
<span style="white-space:pre"> </span>memset(&abort_action,0,sizeof(abort_action));
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if(sigaction(SIGTSTP,NULL,&abort_action)==-1)
<span style="white-space:pre"> </span>perror("Failed to get old handler for SIGTSTP");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>abort_action.sa_handler=&abort_transfer; //将信号处理函数设为abort_transfer
<span style="white-space:pre"> </span>if(sigaction(SIGTSTP,&abort_action,NULL)==-1)
<span style="white-space:pre"> </span>perror("Failed to unignore SIGTSTP");
}
void terminal_echo_off(int fd)
{
<span style="white-space:pre"> </span>struct termios old_terminal;
<span style="white-space:pre"> </span>tcgetattr(fd,&old_terminal);
<span style="white-space:pre"> </span>old_terminal.c_lflag&=~ECHO;
<span style="white-space:pre"> </span>tcsetattr(fd,TCSAFLUSH,&old_terminal);
}
void terminal_echo_on(int fd)
{
<span style="white-space:pre"> </span>struct termios old_terminal;
<span style="white-space:pre"> </span>tcgetattr(fd,&old_terminal);
<span style="white-space:pre"> </span>old_terminal.c_lflag|=ECHO;
<span style="white-space:pre"> </span>tcsetattr(fd,TCSAFLUSH,&old_terminal);
}
void abort_transfer(int signal_number)
{
<span style="white-space:pre"> </span>char res_buffer[BUFSIZE];
<span style="white-space:pre"> </span>int status,fin=0;
<span style="white-space:pre"> </span>if(data_flag) //信号发生时正在传输数据
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>ctrl_z=1;
<span style="white-space:pre"> </span>send_ftpcmd(sockfd_cmd,"ABOR",NULL);
<span style="white-space:pre"> </span>status=get_ftpcmd_status(sockfd_cmd,res_buffer); //426表示ABOR命令成功
<span style="white-space:pre"> </span>}
}
static void bail(const char *on_what)<span style="white-space:pre"> </span>//错误报告函数
{
<span style="white-space:pre"> </span>fputs(strerror(errno),stderr);
<span style="white-space:pre"> </span>fputs(": ",stderr);
<span style="white-space:pre"> </span>fputs(on_what,stderr);
<span style="white-space:pre"> </span>fputc('\n',stderr);
}
linuxFTP客户端详解
最新推荐文章于 2024-06-20 10:40:07 发布