文件传输协议的服务器

三、服务器功能实现与关键函数

1.头文件信息

头文件ftp.h包含系统信息:

#ifndef __FTP_H_

#define __FTP_H_

 

#define COMMAND_NUM 7

 

#define FILE_TRANS_MODE_ASIC 0

 

#define FILE_TRANS_MODE_BIN 1

 

char clientCommand[COMMAND_NUM][20]={{"pwd"}, {"quit"},{'?'},{"ls"},{"cd"}, {"get"},{"put"}};

 

char serverInfo220[]="220 myFTP Server ready.../r/n";

char serverInfo230[]="230 User logged in, proceed./r/n";

char serverInfo331[]="331 User name okay, need password./r/n";

char serverInfo221[]="221 Goodbye!/r/n";

char serverInfo150[]="150 File status okay; about to open data connection./r/n";

char serverInfo226[]="226 Closing data connection./r/n";

char serverInfo200[]="200 Command okay./r/n";

char serverInfo215[]="215 Unix Type FC5./r/n";

char serverInfo213[]="213 File status./r/n";

char serverInfo211[]="211 System status, or system help reply./r/n";

char serverInfo350[]="350 Requested file action pending further information./r/n";

char serverInfo530[]="530 Not logged in./r/n";

char serverInfo531[]="531 Not root client. Anonymous client./r/n";

 

char serverInfo[]="202 Command not implemented, superfluous at this site./r/n";

 

#endif

 

2.处理客户端命令

定义权限用户名及密码:

const char       default_user[] = "root";

const char       default_pass[] = "1234";

 

定义匿名用户及密码:

const char      anony_user[]="anonymous";

const char      anony_pass[]="anonymous";

 

函数*Handle_Client_Request(void* arg)处理客户需求,从客户端连接成功开始到结束服务。其中调用do_client_work(info->client_sock,info->client)函数与客户端交互。

void *Handle_Client_Request(void* arg)

{

       struct ARG*info;

       info=(struct ARG*)arg;

       printf("You got a connection from %s/n",inet_ntoa(info->client.sin_addr));

      

       do_client_work(info->client_sock,info->client);

      

       close(info->client_sock);

       pthread_exit(NULL);

}

函数do_client_work(int client_sock,struct sockaddr_in client)处理FTP各种命令。

void do_client_work(int client_sock,struct sockaddr_in client)

{

       int login_flag;

       login_flag=login(client_sock);

       while(recv_client_info(client_sock)&&login_flag==1)//缺省用户操作响应

       {

              if((strncmp("quit", client_Control_Info, 4) == 0)||(strncmp("QUIT", client_Control_Info, 4) == 0))

              {    

                            send_client_info(client_sock, serverInfo221, strlen(serverInfo221));

                            break;

              }

              else if((strncmp("close",client_Control_Info,5) == 0)||(strncmp("CLOSE",client_Control_Info,5) == 0))

              {

                     printf("Client Quit!/n");

                     shutdown(client_sock,SHUT_WR);

//关闭连接服务器,只关闭写操作。此时仍可进行客户端相关操作。

              }

             

              else if(strncmp("pwd", client_Control_Info, 3) == 0||(strncmp("PWD", client_Control_Info, 3) == 0))

              {    

                            char       pwd_info[MSG_INFO];

                       char       tmp_dir[DIR_INFO];

                         snprintf(pwd_info, MSG_INFO, "257 /"%s/" is current location./r/n", getcwd(tmp_dir, DIR_INFO));

                            send_client_info(client_sock, pwd_info, strlen(pwd_info));

              }

              else if(strncmp("cwd", client_Control_Info, 3) == 0||(strncmp("CWD", client_Control_Info, 3) == 0))

              {

                            handle_cwd(client_sock);

              }

else if(strncmp("mkd", client_Control_Info, 3) == 0||(strncmp("MKD", client_Control_Info, 3) == 0))

              {

                            handle_mkd(client_sock);

              }

else if(strncmp("rmd", client_Control_Info, 3) == 0||(strncmp("RMD", client_Control_Info, 3) == 0))

              {

                            handle_rmd(client_sock);

              }

else if(strncmp("dele", client_Control_Info, 4) == 0||(strncmp("DELE", client_Control_Info, 4) == 0))

              {

                            handle_del(client_sock);

              }

 

              else if(strncmp("pasv", client_Control_Info, 4) == 0||(strncmp("PASV", client_Control_Info, 4) == 0))

              {

                        handle_pasv(client_sock,client);

              }

              else if(strncmp("list", client_Control_Info, 4) == 0||(strncmp("LIST", client_Control_Info, 4) == 0))

              {

                        handle_list(client_sock);

                        send_client_info(client_sock,serverInfo226, strlen(serverInfo226));    

              }

              else if(strncmp("type", client_Control_Info, 4) == 0||(strncmp("TYPE", client_Control_Info, 4) == 0))

              {

                            if(strncmp("type I", client_Control_Info, 6) == 0||(strncmp("TYPE I", client_Control_Info, 6) == 0))

                                         translate_data_mode=FILE_TRANS_MODE_BIN;

                           send_client_info(client_sock, serverInfo200, strlen(serverInfo200));

              }

              else if(strncmp("retr", client_Control_Info, 4) == 0||(strncmp("RETR", client_Control_Info, 4) == 0))

              {

                            handle_file(client_sock);

                            send_client_info(client_sock,serverInfo226, strlen(serverInfo226));  

              }

              else if(strncmp("stor", client_Control_Info, 4) == 0||(strncmp("STOR", client_Control_Info, 4) == 0))

              {

                            handle_file(client_sock);

                            send_client_info(client_sock,serverInfo226, strlen(serverInfo226));  

              }

              else if(strncmp("syst", client_Control_Info, 4) == 0||(strncmp("SYST", client_Control_Info, 4) == 0))

              {

                            send_client_info(client_sock, serverInfo215, strlen(serverInfo215));

              }

              else if(strncmp("size", client_Control_Info, 4) == 0||(strncmp("SIZE", client_Control_Info, 4) == 0))

              {

                            send_client_info(client_sock, serverInfo213, strlen(serverInfo213));

              }

              else if(strncmp("feat", client_Control_Info, 4) == 0||(strncmp("FEAT", client_Control_Info, 4) == 0))

              {

                            send_client_info(client_sock, serverInfo211, strlen(serverInfo211));

              }

              else if(strncmp("rest", client_Control_Info, 4) == 0||(strncmp("REST", client_Control_Info, 4) == 0))

              {

                            send_client_info(client_sock, serverInfo350, strlen(serverInfo350));

              }

              else

              {

                            send_client_info(client_sock, serverInfo, strlen(serverInfo));

              }

             

       }

       while(recv_client_info(client_sock)&&(login_flag == 2))//匿名用户操作响应

{

//省略代码

}

}

 

 

函数int login(int client_sock)为登陆函数。处理客户端登录请求,与已定义的权限用户密码进行匹配,成功则为ROOT用户,失败则匹配匿名用户,匿名用户只能进行简单服务。

       if(strncmp(format_client_Info, default_user, 4) == 0)

       {

              flag=1;

       }

       if(strncmp(format_client_Info, anony_user, 9) == 0)

    {

                flag=2;

}

 

函数void handle_cwd(int client_sock)处理转换目录功能。

关键代码:

if (chdir(client_dir) >= 0)

                  {

                  snprintf(cwd_info, MSG_INFO, "257 /"%s/" is current location./r/n", getcwd(tmp_dir, DIR_INFO));

                  send_client_info(client_sock, cwd_info, strlen(cwd_info));

                  }

             else

                  {

                    snprintf(cwd_info, MSG_INFO, "550 %s :%s/r/n",client_dir,strerror(errno));

                    perror("chdir():");

                    send_client_info(client_sock, cwd_info, strlen(cwd_info));

                  }               

上述代码表示当转换目录存在则把当前目录更改为转换目录,否则报错。

创建目录与删除目录关键代码与之类似。

函数void handle_mkd(int client_sock)处理创建目录功能。

关键代码:

if (mkdir(client_dir) >= 0)

                  {

                  printf(" /"%s/" is created successfully./r/n", client_dir);

                  send_client_info(client_sock, mkd_info, strlen(mkd_info));

                  }

             else

                  {

                    snprintf(mkd_info, MSG_INFO, "550 %s :%s/r/n",client_dir,strerror(errno));

                    perror("mkdir():");

                    send_client_info(client_sock, mkd_info, strlen(mkd_info));

                  }               

上述代码表示创建client_dir目录,成功输出消息,否则报错。

 

函数void handle_rmd(int client_sock)处理删除目录功能。

关键代码:

if (rmdir(client_dir) >= 0)

                  {

                  printf(" /"%s/" is deleted successfully./r/n", client_dir);

                  send_client_info(client_sock, rmd_info, strlen(rmd_info));

                  }

             else

                  {

                    snprintf(rmd_info, MSG_INFO, "550 %s :%s/r/n",client_dir,strerror(errno));

                    perror("rmdir():");

                    send_client_info(client_sock, rmd_info, strlen(rmd_info));

                  }               

上述代码表示删除client_dir目录,成功输出消息,否则报错。

 

函数handle_list(int client_sock)处理list命令。

       FILE *pipe_fp;//建立管道以传输数据

char t_dir[DIR_INFO];

       char list_cmd_info[DIR_INFO];

       snprintf(list_cmd_info, DIR_INFO, "ls -l %s", getcwd(t_dir, DIR_INFO));//得到当前目录

      

     if ((pipe_fp = popen(list_cmd_info, "r")) == NULL)//打开管道

           {

              printf("pipe open error in cmd_list/n");

              return ;

           }

     printf("pipe open successfully!, cmd is %s/n", list_cmd_info);

 

       char t_char;

     while ((t_char = fgetc(pipe_fp)) != EOF)

           {

              printf("%c", t_char);

              write(t_data_sock, &t_char, 1);

           }//得到当前目录文件列表

     pclose(pipe_fp);//关闭管道

     printf("close pipe successfully!/n");     

     close(t_data_sock);

       printf("%s close data successfully!/n",serverInfo226);

       close(ftp_data_sock);    

 

函数struct sockaddr_in create_date_sock()创建数据sock

struct sockaddr_in create_date_sock()

{

       int t_client_sock;

       struct sockaddr_in t_data_addr;

      t_client_sock = socket(AF_INET, SOCK_STREAM, 0);//创建客户数据SOCK

     if (t_client_sock < 0)

           {

              printf("create data socket error!/n");

              return;

           }

    srand((int)time(0));

    int a=rand()%1000+1025;

    bzero(&t_data_addr, sizeof(t_data_addr));

    t_data_addr.sin_family = AF_INET;

    t_data_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    t_data_addr.sin_port = htons(a);   

      

    if (bind(t_client_sock, (struct sockaddr*)&t_data_addr, sizeof(struct sockaddr)) < 0)

            {

                     printf("bind error in create data socket:%s/n",strerror(errno));

                     return;

             }

    listen(t_client_sock, LISTEN_QENU);

   

    ftp_data_sock=t_client_sock;

    return t_data_addr;

}

 

3.处理文件类命令

函数void handle_file(int client_sock)处理文件功能。把上传下载功能集成在一个函数中实现。

关键代码:

FILE* fp;//建立管道处理文件信息

       int file_fd;

       int n;

       char t_dir[DIR_INFO];

      

       char file_info[DIR_INFO];

      

       snprintf(file_info, DIR_INFO, "%s/%s", getcwd(t_dir, DIR_INFO),format_client_Info);

//获得文件信息

 

if(strncmp(getcwd(t_dir, DIR_INFO),format_client_Info,strlen(getcwd(t_dir, DIR_INFO))-1)==0)

              fp = fopen(format_client_Info, file_mode); //打开文件

       else

              fp = fopen(file_info, file_mode);

 

if(strncmp("retr", client_Control_Info, 4) == 0||(strncmp("RETR", client_Control_Info, 4) == 0))

     {

              while ((n = read(cmd_sock, client_Data_Info, MAX_INFO)) > 0)

              {//读写文件

                  if (write(t_data_sock, client_Data_Info, n) != n)

                         {

                            printf("retr transfer error/n");

                            return;

                    }

              }

       }

       else

       {

              while ((n = read(t_data_sock, client_Data_Info, MAX_INFO)) > 0)

              {

                  if (write(cmd_sock, client_Data_Info, n) != n)

                         {

                            printf("stor transfer error/n");

                            return;

                    }

              }

       }

       fclose(fp);    //关闭传输管道

   close(t_data_sock);  //关闭数据sock

   close(ftp_data_sock);       //关闭FTPsock

 

函数void send_client_info(int client_sock,char* info,int length)发送客户端信息。

函数int recv_client_info(int client_sock)接收客户端信息。

void send_client_info(int client_sock,char* info,int length)

{

   int len;

       if((len = send(client_sock, info, length,0))<0)

       {

                     perror("send info error ");

                     return;

       }    

}

int recv_client_info(int client_sock)

{

   int num;

       if((num=recv(client_sock,client_Control_Info,MAX_INFO,0))<0)

       {

                     perror("receive info error ");

                     return;

       }

       client_Control_Info[num]='/0';

       printf("Client %d Message:%s/n",pthread_self(),client_Control_Info);

       if(strncmp("USER", client_Control_Info, 4) == 0||strncmp("user", client_Control_Info, 4) == 0)return 2;

       return 1;

}

 

函数void handle_del(int client_sock)处理删除目录功能。

关键代码:

if (unlink(client_file) >= 0)

                  {

                  printf(" /"%s/" is deleted successfully./r/n", client_file);

                  send_client_info(client_sock, del_info, strlen(del_info));

                  }

             else

                  {

                    snprintf(del_info, MSG_INFO, "550 %s :%s/r/n",client_file,strerror(errno));

                    perror("unlink():");

                    send_client_info(client_sock, del_info, strlen(del_info));

                  }               

上述代码表示删除文件client_file,成功输出消息,否则报错

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值