实验13简单FTP 程序设计 |
实验目的:设计一个简单的FTP 客户端,支持用户登录,浏览目录列表,上传 文件和下载文件的功能。 |
实验内容: 程序的伪代码如下: (假定FTP 用户名为user_name,密码为pass_word) 主函数: 1 连接FTP 服务器的21 端口 2 等待FTP 服务器回应,若应答码不为220,则报错 3 向FTP 服务器21 端口发送"USER user_name\r\n"字符串,等待FTP 回应,若 应答码不为331,则报错。 4 向FTP 服务器21 端口发送"PASS pass_word\r\n"字符串,等待FTP 回应,若应 答码不为230,则报错:用户与密码不匹配。 while(1) { 5 等待用户输入命令cmd; 6 若cmd 为quit,则关闭套接字,退出程序 7 若cmd 为ls 或dir则list_file(sock) 8 若cmd 为put abc.xyz,则调用up_file(sock,abc.xyz) 9 若cmd 为get abc.xyz,则调用down_file(sock,abc.xyz) } |
/* 函数名list_file 函数功能:显示ftp 服务器上文件列表 @sock : ftp 服务器控制端口对应的套接字 */ 函数list_file(int sock) { //该sock 对应了ftp 的21 端口 1 向sock 发送"TYPE I\r\n",等待应答码200 2 向sock 发送"PASV\r\n",等待应答码227 3 将sock 发送过来的字符串中寻找形如(xx,xx,xx,xx,xx, xx)的子串,从该字符串 中提取IP 地址和端口号。建立新套接字sock2,连接该IP 地址和端口号。 4 向sock 发送"LIST\r\n" 5 从sock2 中读取字符串,直到对方关闭 |
6 从sock 中读取回应码,若不为226,则报错 } |
/* 函数名up_file 函数功能:上传本地文件到ftp 服务器 @sock : ftp 服务器控制端口对应的套接字 @args: 要上传的文件名 */ |
函数up_file(int sock,char args) { 1 在本地打开args 对应的文件,其文件指针为fp1 2 向sock 发送"TYPE I\r\n",等待应答码200 3 向sock 发送"PASV\r\n",等待应答码227 4 将sock 发送过来的字符串中寻找形如(xx,xx,xx,xx,xx,xx)的子串,从该字符串 中提取IP 地址和端口号。建立新套接字sock2,连接该IP 地址和端口号。 5 向sock 发送"STOR args 对应文件名\r\n" 6 将fp1 指向的文件逐字节的读出,并且写入sock2 中,写完后关闭sock2 7 等待sock 的回应,回应码为226 } |
/* 函数名up_file 函数功能:下载ftp 服务器文件到本地 @sock : ftp 服务器控制端口对应的套接字 @args: 要下载的文件名 */ 函数down_file(int sock,char args) { 1 在本地打开args 对应的文件,其文件指针为fp1 2 向sock 发送"TYPE I\r\n",等待应答码200 3 向sock 发送"PASV\r\n",等待应答码227 4 将sock 发送过来的字符串中寻找形如(xx,xx,xx,xx,xx,xx)的子串,从该字符串 中提取IP 地址和端口号。建立新套接字sock2,连接该IP 地址和端口号。 5 向sock 发送"SIZE args 对应文件名\r\n" ,若回应码不为213,则没有这个文件 或通信过程出错。 6 向sock 发送"RETR args 对应文件名\r\n" 。 7 将sock2 中内容逐字节的读出,并且写入fp1 的文件,写完后关闭sock2 和fp1 8 等待sock 的回应,回应码应该为226,否则报错 } |
附录: 代码实现: #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include <netdb.h> #include <pwd.h> #include <termios.h> |
#define BUFSIZE 1024 char buf[BUFSIZE]; char sendbuf[BUFSIZE]; |
void err_sys(char *s) { printf("%s",s); exit(-1); }; void err_sysa(int a,char *s) { printf("status=%d %s",a,s); exit(-1); }; |
void terminal_echo_off(int fd) { struct termios oldterm; tcgetattr(fd,&oldterm); oldterm.c_lflag &=~ECHO; tcsetattr(fd,TCSAFLUSH,&oldterm); }; int active_listen() { int sockfd; sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) fprintf(stderr,"socket error!"); struct sockaddr_in localaddr; |
localaddr.sin_family=AF_INET; inet_aton("0.0.0.0",&localaddr.sin_addr); localaddr.sin_port=0; |
int bret=bind(sockfd,(struct sockaddr*)&localaddr,sizeof localaddr); if(bret==-1)printf("bind error!\r\n"); return sockfd; |
}; |
unsigned int get_port(int fd) { struct sockaddr_in sa; unsigned int port; int sin_size=sizeof(struct sockaddr_in); getsockname(fd,(struct sockaddr*)&sa,&sin_size); port=ntohs(sa.sin_port); return port; }; void hexprint(char *x) { int i=0; |
while(x[i]!=0) { |
printf("%x ",x[i]); i++; |
} printf("\r\n"); |
}; void terminal_echo_on(int fd) { struct termios oldterm; tcgetattr(fd,&oldterm); oldterm.c_lflag |= ECHO; tcsetattr(fd,TCSAFLUSH,&oldterm); }; |
void getaddrin(struct sockaddr_in *pdest) { char *start=strchr(buf,'('); start++; char *end=strchr(buf,')'); |
*end=0; char *pi; for(pi=start;pi<end;pi++) if(*pi==',')*pi=' '; char ci1[4],ci2[4],ci3[4],ci4[4],ci5[4],ci6[4]; int c1,c2,c3,c4,c5,c6; |
sscanf(start,"%s%s%s%s%s%s",ci1,ci2,ci3,ci4,ci5,ci6); c1=atoi(ci1); c2=atoi(ci2); c3=atoi(ci3); c4=atoi(ci4); c5=atoi(ci5); c6=atoi(ci6); |
int ip=c1<<24|c2<<16|c3<<8|c4; short port=c5<<8|c6; struct sockaddr_in dest; pdest->sin_family=AF_INET; pdest->sin_port=htons(port); pdest->sin_addr.s_addr=htonl(ip); |
}; |
void sendftp(const char* cmd,int fd) { sprintf(sendbuf,cmd); write(fd,sendbuf,strlen(sendbuf)); }; |
void down_file(int sock,const char* args) { //下载文件 sendftp("TYPE I\r\n",sock); int ftp_status=recvftp(sock); if(ftp_status!=200){printf("ftp_status=%d\r\n",ftp_status);err_sys("类型错误 \r\n");}; sendftp("PASV\r\n",sock); ftp_status=recvftp(sock); if(ftp_status!=227)err_sys("进入被动模式错误\r\n"); struct sockaddr_in dest; getaddrin(&dest);//通过被动模式,设置要连接的地址和端口 |
int fsock=socket(AF_INET,SOCK_STREAM,0); |
if(fsock<=0)err_sys("socket2 创建错误\r\n"); if(connect(fsock,(struct sockaddr*)&dest,sizeof(dest))==-1)err_sys("无法连接 FTP 控制端口\r\n"); char tempbuf[512]; sprintf(tempbuf,"SIZE /%s\r\n",args); sendftp(tempbuf,sock); ftp_status=recvftp(sock); |
if(ftp_status==213) { sprintf(tempbuf,"RETR /%s\r\n",args); sendftp(tempbuf,sock); ftp_status=recvftp(sock); if(ftp_status!=150)err_sys("RETR 错误!\r\n"); FILE * fp=fopen(args,"w+"); printf("%s\r\n",args); if(fp==NULL)err_sys("nihaod"); while(1) { int n=read(fsock,buf,BUFSIZE); if(n<=0)break; fwrite(buf,sizeof(char),n,fp); } fflush(fp); fclose(fp); printf("文件下载完毕\r\n"); ftp_status=recvftp(sock); if(ftp_status!=226)err_sysa(ftp_status,"文件传输错误226!\r\n"); |
} else if(ftp_status==550) { printf("没有这个文件%s\r\n",args); } else err_sys("错误ftp 代码"); close(fsock); |
}; |
void up_file(int sock,const char* args) { FILE * fp=fopen(args,"r"); printf("%s\r\n",args); if(fp==NULL){printf("无此文件\r\n");return;}; |
int flen; fseek(fp,0,SEEK_END); flen=ftell(fp); fseek(fp,0,SEEK_SET); |
//上传文件 sendftp("TYPE I\r\n",sock); int ftp_status=recvftp(sock); if(ftp_status!=200){printf("ftp_status=%d\r\n",ftp_status);err_sys("类型错误 \r\n");}; sendftp("PASV\r\n",sock); ftp_status=recvftp(sock); if(ftp_status!=227)err_sys("进入被动模式错误\r\n"); struct sockaddr_in dest; getaddrin(&dest);//通过被动模式,设置要连接的地址和端口 |
int fsock=socket(AF_INET,SOCK_STREAM,0); if(fsock<=0)err_sys("socket2 创建错误\r\n"); if(connect(fsock,(struct sockaddr*)&dest,sizeof(dest))==-1)err_sys("无法连接 FTP 控制端口\r\n"); char tempbuf[512]; |
sprintf(tempbuf,"STOR /%s\r\n",args); sendftp(tempbuf,sock); ftp_status=recvftp(sock); if(ftp_status!=150)err_sys("STOR 错误!\r\n"); FILE* sockfp=fdopen(fsock,"w"); if(sockfp==NULL)err_sys("sockfp 错误\r\n"); |
int i; for(i=0;i<flen;i++) fputc(fgetc(fp),sockfp); fflush(sockfp); fclose(sockfp); fclose(fp); ftp_status=recvftp(sock); if(ftp_status!=226)err_sysa(ftp_status,"文件传输错误226!\r\n"); printf("文件上传完毕\r\n"); close(fsock); }; |
void list_file(int sock) { |
sendftp("TYPE I\r\n",sock); int ftp_status=recvftp(sock); if(ftp_status!=200){printf("ftp_status=%d\r\n",ftp_status);err_sys("类型错误 \r\n");}; sendftp("PASV\r\n",sock); ftp_status=recvftp(sock); if(ftp_status!=227)err_sys("进入被动模式错误\r\n"); struct sockaddr_in dest; getaddrin(&dest); int fsock=socket(AF_INET,SOCK_STREAM,0); if(fsock<=0)err_sys("socket2 cuo wu\r\n"); if(connect(fsock,(struct sockaddr*)&dest,sizeof(dest))==-1)err_sys("wu fa lianjian dui fang\r\n"); |
sendftp("LIST\r\n",sock); ftp_status=recvftp(sock); if(ftp_status!=150)err_sys("打开文件错误!\r\n"); while(1) { int n=read(fsock,buf,BUFSIZE); if(n<=0)break; buf[n]=0; printf("%s",buf); } ftp_status=recvftp(sock); if(ftp_status!=226)err_sysa(ftp_status,"226 错误(250)!\r\n"); close(fsock); |
} |
int checkcode(const int s,const int t) { if(s==t) { return 1; } else { printf("wrong code!\r\n"); } return 0; } int recvftp(int fd) |
{ |
//返回ftp 代码,并且将所有字符串写在buf 中 int n=read(fd,buf,BUFSIZE); char stabuf[4]; buf[n]=0; sscanf(buf,"%3s",stabuf); int ftpcode=atoi(stabuf); if(ftpcode<=0)err_sys("返回码错误\r\n"); return ftpcode; |
} void promt(const char* s,char *cmd) { printf("%s",s); fgets(cmd,32,stdin); } int main(int argc,char* argv[]) { char cmd[32]; int ftp_status=0;//ftp 服务器返回码 struct hostent *host; if((host=gethostbyname(argv[1]))==NULL) err_sys("Get hostanme error!\r\n"); |
int port=atoi(argv[2]); if(argc==3&&port<0) { fprintf(stderr,"Usage:%s hostname portnumber\r\n",argv[0]); exit(-1); } |
/*生成套接字*/ int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<=0)err_sys("socket error!\r\n"); |
/*FTP 服务器套接字地址*/ struct sockaddr_in server_addr; server_addr.sin_family=AF_INET; server_addr.sin_port=htons(port); server_addr.sin_addr=*((struct in_addr*)host->h_addr); |
/*连接服务器*/ int conret=connect(sock,(struct sockaddr*)&server_addr,sizeof server_addr); if(conret==-1) { |
fprintf(stderr,"connect error:%s\r\n",strerror(errno)); exit(-1); |
} |
/*获得FTP 返回码*/ ftp_status=recvftp(sock); if(ftp_status!=220)err_sys("登录错误无法连接!220 \r\n"); |
printf("请输入[%s]用户名:(直接回车为默认的anonymous) ",inet_ntoa(server_addr.sin_addr)); fgets(cmd,sizeof(cmd),stdin); //scanf(cmd,"%s"); cmd[strlen(cmd)-1]=0;//最后一个字符是0a,所以要去掉 if(strlen(cmd)!=0) { sprintf(sendbuf,"USER %s\r\n",cmd); sendftp(sendbuf,sock); ftp_status=recvftp(sock); if(ftp_status!=331)err_sys("登录错误无法连接! 331\r\n"); |
terminal_echo_off(STDIN_FILENO); printf("请输入密码: "); fgets(cmd,sizeof(cmd),stdin); terminal_echo_on(STDIN_FILENO); cmd[strlen(cmd)-1]=0;//最后一个字符是0a,所以要去掉 sprintf(sendbuf,"PASS %s\r\n",cmd); sendftp(sendbuf,sock); ftp_status=recvftp(sock); if(ftp_status!=230)err_sys("密码错误230\r\n"); } else { sendftp("USER anonymous\r\n",sock); ftp_status=recvftp(sock); sendftp("PASS IEUSER@\r\n",sock); ftp_status=recvftp(sock); if(ftp_status!=230)err_sys("不支持匿名登录\r\n"); } printf("建立和ftp 服务器的连接\r\n"); /*进入被动模式*/ |
char totalcmd[512]; |
本文转自陈仲阳0 51CTO博客,原 while(1) { while(1) { promt("请输入命令:",totalcmd); sscanf(totalcmd,"%s%s",cmd,args); if(cmd==NULL){printf("输入命令错误,重新输入命令");continue;}; if(strcasecmp(cmd,"quit")==0) { printf("退出程序!\r\n"); close(sock); exit(0); } break; } |
if(strcasecmp(cmd,"ls")==0||strcasecmp(cmd,"dir")==0) list_file(sock); |
if(strcasecmp(cmd,"GET")==0)down_file(sock,args); |
if(strcasecmp(cmd,"PUT")==0)up_file(sock,args); |
本文转自陈仲阳0 51CTO博客,原文链接:http://blog.51cto.com/wolfword/1240349