实验13 简单FTP 程序设计
實驗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]; |
char args[256]; 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); |
} } |
轉載于:https://blog.51cto.com/wolfword/1240349
總結
以上是生活随笔為你收集整理的实验13 简单FTP 程序设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android inline hook手
- 下一篇: Java中的字符串驻留