linuxFTP客户端详解

#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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值