天天看点

实验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 服务器

@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