实验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 服务器
@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)的子串,从该字符串
5 向sock 发送"STOR args 对应文件名\r\n"
6 将fp1 指向的文件逐字节的读出,并且写入sock2 中,写完后关闭sock2
7 等待sock 的回应,回应码为226
函数功能:下载ftp 服务器文件到本地
@args: 要下载的文件名
函数down_file(int sock,char args)
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);
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)
oldterm.c_lflag |= ECHO;
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);
if(ftp_status==213)
sprintf(tempbuf,"RETR /%s\r\n",args);
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");
int n=read(fsock,buf,BUFSIZE);
if(n<=0)break;
fwrite(buf,sizeof(char),n,fp);
fflush(fp);
fclose(fp);
printf("文件下载完毕\r\n");
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");
if(fp==NULL){printf("无此文件\r\n");return;};
int flen;
fseek(fp,0,SEEK_END);
flen=ftell(fp);
fseek(fp,0,SEEK_SET);
//上传文件
sprintf(tempbuf,"STOR /%s\r\n",args);
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);
printf("文件上传完毕\r\n");
void list_file(int sock)
getaddrin(&dest);
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);
if(ftp_status!=150)err_sys("打开文件错误!\r\n");
buf[n]=0;
printf("%s",buf);
if(ftp_status!=226)err_sysa(ftp_status,"226 错误(250)!\r\n");
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];
sscanf(buf,"%3s",stabuf);
int ftpcode=atoi(stabuf);
if(ftpcode<=0)err_sys("返回码错误\r\n");
return ftpcode;
void promt(const char* s,char *cmd)
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]);
/*生成套接字*/
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));
/*获得FTP 返回码*/
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);
if(ftp_status!=331)err_sys("登录错误无法连接! 331\r\n");
terminal_echo_off(STDIN_FILENO);
printf("请输入密码: ");
terminal_echo_on(STDIN_FILENO);
sprintf(sendbuf,"PASS %s\r\n",cmd);
if(ftp_status!=230)err_sys("密码错误230\r\n");
sendftp("USER anonymous\r\n",sock);
sendftp("PASS IEUSER@\r\n",sock);
if(ftp_status!=230)err_sys("不支持匿名登录\r\n");
printf("建立和ftp 服务器的连接\r\n");
/*进入被动模式*/
char totalcmd[512];
本文转自陈仲阳0 51CTO博客,原
char args[256];
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