一个ftp客户端的实现

来源:互联网 发布:python documentation 编辑:程序博客网 时间:2024/05/17 08:15

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h> 

#include <fcntl.h>

#include <sys/types.h>

#include <dirent.h> 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <termios.h>

#include <curses.h>

#include <netdb.h>



#define FTP_DEFAULT_PORT 21


#define SUCCESS 0


#define MAX_STR_LEN 64


#define MAX_BUF_LEN 4096


#define MAX_FILE_NAME 255



fd_set infds;


struct sockaddr_in ftp_server, local_host;


struct sockaddr_in Ftp_Server_ctrl_addr; 


struct sockaddr_in Ftp_Server_data_addr; 


int sockfd_ctrl;          


int sockfd_data;        


char ServerIP[MAX_STR_LEN];     

 

int ServerPort;     

  

char User[MAX_STR_LEN];     


char Password[MAX_STR_LEN]; 


char MsgBuffer[MAX_BUF_LEN];


char DataBuffer[MAX_BUF_LEN];


int  passive_flag = 0;


static struct termios stored_settings;



enum com_type

{

    list,

    put,

    get

};


struct  soc_set_struct

{

    int  soc;


    enum com_type  type;


    int  handle;

};


struct soc_set_struct soc_set[5];

int ErrorExit(constchar* error)

{

  printf("Error: %s\n",error);

  exit(-1);

}

int  isPassive()

{

    if(passive_flag ==0)

        return0;

    else

        return1;

}


int mygetch( ) {

    struct termios oldt,

    newt;

    int ch;

    tcgetattr( STDIN_FILENO, &oldt );

    newt = oldt;

    newt.c_lflag &= ~( ICANON | ECHO );

    tcsetattr( STDIN_FILENO, TCSANOW, &newt );

    ch = getchar();

    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );

    return ch;

}


int SendControlCommand(constchar* cmd_code,constchar* cmd_para)

{

    char SendBuffer[MAX_BUF_LEN];

    int Length;

    int SendRes;

    memset(SendBuffer, 0, MAX_BUF_LEN);

    if(cmd_code)

    {

        strcpy(SendBuffer,cmd_code);

        if(cmd_para)

        {

            strcat(SendBuffer," ");

            strcat(SendBuffer,cmd_para);

            strcat(SendBuffer,"\r\n");

        }

        else

            strcat(SendBuffer,"\r\n");


            Length=strlen(SendBuffer);

            SendRes = write(sockfd_ctrl,SendBuffer,Length);

    }

    return SendRes;

}

int GetReplyMsg(void)

{

  int count;

  int reply;

  memset(MsgBuffer, 0, MAX_BUF_LEN);

  count = read(sockfd_ctrl,MsgBuffer,MAX_BUF_LEN);

  reply = atoi(MsgBuffer);

  printf("[Server reply]    %s", MsgBuffer);

  return reply;

}

int ftp_sendcmd_re( int sock, char *cmd,void *re_buf, ssize_t *len)

{

    char        buf[512];

    ssize_t     r_len;

    

    if ( send( sock, cmd, strlen(cmd),0 ) == -1 )

        return -1;

    

    r_len = recv( sock, buf, 512,0 );

    if ( r_len <1 )return -1;

    buf[r_len] = 0;

    

    if (len !=NULL) *len = r_len;

    if (re_buf !=NULL) sprintf(re_buf,"%s", buf);

    

    return0;

}

int ftp_sendcmd( int sock,char *cmd )

{

    char     buf[512];

    int      result;

    ssize_t  len;

    

    result = ftp_sendcmd_re(sock, cmd, buf, &len);

    if (result ==0)

    {

        sscanf( buf, "%d", &result );

    }

    

    return result;

}

void GetUserAccount(void)                    

{

  char buf[MAX_BUF_LEN];

  mygetch();

  printf("User:(Press Enter for anonymous):");

    fgets(buf,sizeof(buf),stdin);

    if(buf[0]=='\n')

        strncpy(User,"anonymous",9);

    else

        strncpy(User,buf,strlen(buf) - 1);

//  printf("User:%s\n",User);


}

void GetUserPasswd(void)              

{

  char buf[MAX_BUF_LEN];

  printf("Password:(Press Enter for anonymous):");

  char ch;

  int  index =0;

    while(1)

  {

      ch = mygetch();

      if(ch =='\n')

      {

        break;

      }

      buf[index] = ch;

      index++;

      printf("*");

  }


  printf("\n");



  buf[index] = '\0';


  if(buf[0]=='\n')

      strncpy(Password,"anonymous",9);

  else

      strncpy(Password,buf,strlen(buf));


  printf("%s",Password);

}


int FTP_Login(void)                    //  test ok

{

  GetUserAccount();

  SendControlCommand("USER",User);

  GetReplyMsg();

  GetUserPasswd();

  SendControlCommand("PASS",Password);

  if(230 == GetReplyMsg())

    return SUCCESS;

  else 

    ErrorExit("can't login");

}

void GetConnectMode()

{

    int choice;

    printf("select passvice or assive (0 : 1)\n");


    scanf("%d",&choice);


    passive_flag = choice;

}



void GetServerIP(void)                

{

  char buf[MAX_BUF_LEN];

  int  choice =0;

    


  printf("input the IP or domain name (0 : 1):");


  scanf("%d",&choice);


  mygetch();


  if(choice ==0)  

  {


    printf("Please input the Server's IP :");

    fgets(buf,sizeof(buf),stdin);

    if(buf[0]=='\n')

        ErrorExit("did not input IP address!");

    else

        strncpy(ServerIP,buf,strlen(buf)-1);

  }

  else

  {

    printf("Please input the Server's Domain :");

    fgets(buf,sizeof(buf),stdin);


    struct hostent* server = gethostbyname(buf);

    if(!server)

    {

        ErrorExit("get ip address fail\n!");

    }

    else

    {

        strcpy(ServerIP,inet_ntoa(*((struct in_addr*)server->h_addr)));

    }


  }

}

void GetServerPort(void)                           

{

  char buf[MAX_BUF_LEN];

  printf("Please input the Server Port:");

  fgets(buf,sizeof(buf),stdin);

  if(buf[0]=='\n')

    ErrorExit("did not input Server's Port!");

    else

        ServerPort = atoi(buf);

}

void FillServerAddr(constchar* ip,unsignedshortint port,struct sockaddr_in* pServer_addr)

{

  memset(pServer_addr, 0,sizeof(struct sockaddr_in));

  pServer_addr->sin_family = AF_INET;

  pServer_addr->sin_port =  htons(port);

  pServer_addr->sin_addr.s_addr = inet_addr(ip);

}



int rand_local_port()

{

    int local_port;

    srand((unsigned)time(NULL));

    local_port = rand() % 40000 +1025;

    return local_port;

}

int  ftp_asv_connect()

{

   int  lsn_sock;

   int  client_port;

   char cmd_buf[32];

   struct   sockaddr_in  sin;

   struct   sockaddr_in  local;

   int      addr_len =sizeof(struct sockaddr);

   char local_ip[24];

   char *ip_1, *ip_2, *ip_3, *ip_4;

   int  new_sock;

   int  set =sizeof(sin);


   client_port = rand_local_port();


   lsn_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);


   if(lsn_sock == -1)

   {

       printf("Create the listen socket failure\n");

       return -1;

   }


   memset((char *)&local_host,0,sizeof(sin));

   local_host.sin_family  = AF_INET;

   local_host.sin_port = htons(client_port);

   local_host.sin_addr.s_addr =  htonl(INADDR_ANY);


   if(bind(lsn_sock,(struct sockaddr*)&local_host,sizeof(sin)) == -1)

   {

        close(lsn_sock);

        printf("bind to listen the socket failure\n");

        return -1;

   }


   if(listen(lsn_sock,1) == -1)

   {

        close(lsn_sock);

        printf("listen failure\n");

        return -1;

   }

  

   if(getsockname(sockfd_ctrl,(struct sockaddr*)&local,(socklen_t *)&addr_len) <0)

   {

        close(lsn_sock);

        printf("get the local host ip failure\n");

        return -1;

   }

   

   snprintf(local_ip, sizeof(local_ip), inet_ntoa(local.sin_addr));

 

   local_ip[strlen(local_ip)]='\0';

   ip_1 = local_ip;

   ip_2 = strchr(local_ip, '.');

   *ip_2 = '\0';

   ip_2++;

   ip_3 = strchr(ip_2, '.');

   *ip_3 = '\0';

   ip_3++;

   ip_4 = strchr(ip_3, '.');

   *ip_4 = '\0';

   ip_4++;

   snprintf(cmd_buf, sizeof(cmd_buf),"PORT %s,%s,%s,%s,%d,%d", \

                    ip_1, ip_2, ip_3, ip_4, client_port >>8 &0xff, client_port&0xff);


   SendControlCommand(cmd_buf,NULL);

   GetReplyMsg();


   return lsn_sock;

}

int CreateControlConnection()         

{

  /* create socket descriptor*/

  sockfd_ctrl = socket(AF_INET, SOCK_STREAM, 0);

  if(-1 == sockfd_ctrl)

    ErrorExit("Create socket failed!");

  /* connect to the server */

  if(connect(sockfd_ctrl,(struct sockaddr *)&Ftp_Server_ctrl_addr,sizeof(struct sockaddr_in)) == 0)

    {

    printf("Successfully connect to server:ip:%s,port:%d\n",  

     inet_ntoa(Ftp_Server_ctrl_addr.sin_addr) ,ntohs(Ftp_Server_ctrl_addr.sin_port)); 

    }

    else

       ErrorExit("control connect failed!");



    soc_set[0].soc = sockfd_ctrl;


    return0;   

}

int passive()

    char PasvReply[MAX_BUF_LEN];

    char* tmp;

    int count, port;

    SendControlCommand("PASV",NULL);

    count = read(sockfd_ctrl, PasvReply, MAX_BUF_LEN);

    printf("%s", PasvReply);

    if(count <=0)

      return0;

    PasvReply[count] = '\0';

    if(227 == atoi(PasvReply))

    {

      tmp = strrchr(PasvReply, ',');

      port = atoi(tmp+1);

      *tmp = '\0';

      tmp = strrchr(PasvReply, ',');

      port += atoi(tmp+1)*256;

      return port;

    }

    return0;

}

    


int CreateDataConnection()

{

  sockfd_data = socket(AF_INET, SOCK_STREAM, 0);

  if(-1 == sockfd_data)

  ErrorExit("Create socket failed!");

  if(connect(sockfd_data,(struct sockaddr *)&Ftp_Server_data_addr,sizeof(struct sockaddr_in)) == 0)

    {

    printf("Successfully connect to server:ip:%s,port:%d\n",  

     inet_ntoa(Ftp_Server_data_addr.sin_addr) ,ntohs(Ftp_Server_data_addr.sin_port)); 

    }

    else

       ErrorExit("data connect failed!");   

    return0;  

}


void FTP_CMD_START(void)

{

      GetServerIP();

      GetServerPort();

      GetConnectMode();

      FillServerAddr(ServerIP, ServerPort, &Ftp_Server_ctrl_addr);

      CreateControlConnection();

      GetReplyMsg();

      FTP_Login();

}


void FTP_CMD_QUIT(void)

{

   SendControlCommand("QUIT",NULL);

   GetReplyMsg();

   close(sockfd_ctrl);

}



void FTP_CMD_CWD(void)                

{

    char pathname[MAX_FILE_NAME];

    char temp[MAX_FILE_NAME];

    printf("Change to which directory:");

    memset(pathname, 0,sizeof(pathname));

    fgets(temp,sizeof(temp),stdin);

      if(pathname[0]=='\n')

      {

      printf("please input the path name!");

      return;

     }

    else

      strncpy(pathname, temp, strlen(temp)-1);

        SendControlCommand("CWD",pathname);

        GetReplyMsg();

}




void FTP_CMD_LIST(void)          

{

      int result;

      int data_soc;

      int i =0;

      int lis_soc;

      int set =sizeof(local_host);


      if(isPassive() ==0 )

      {

          ServerPort =  passive();

          if(ServerPort >0)

               FillServerAddr(ServerIP, ServerPort, &Ftp_Server_data_addr);

          SendControlCommand("LIST",NULL);

          CreateDataConnection();

          data_soc = sockfd_data;

      }

      else

      {


          lis_soc = ftp_asv_connect();


          SendControlCommand("LIST",NULL);

         

          data_soc  = accept(lis_soc,(struct sockaddr * )&local_host,(socklen_t*)&set);


          if(data_soc  == -1)

          {

              printf("Sorry ,you can't use PORT mode,there is something wrong when the server connect to this\n");

              return ;

          }

      }



      for(i =0; i <5 ; ++i)

      {

          if(soc_set[i].soc == -1)

              break;

      }


      if(i ==5)

      {

          printf("you can't connect to server more than 5\n");

          close(sockfd_data);

      }


      soc_set[i].soc = data_soc;

      soc_set[i].type = list;

}


void FTP_CMD_DOWNLOAD(void)            

{

    char pathname[MAX_FILE_NAME];

    char filename[MAX_FILE_NAME];

    char temp[MAX_FILE_NAME];

    int newfd;

    int res;

    int Counter;

    int data_soc;

    int i =0;

    int result;

    int lis_soc;

    int set =sizeof(local_host);

    printf("Input file name to download:");

    fgets(temp,sizeof(temp),stdin);

      if(temp[0]=='\n')

      {

      printf("please input the file name!");

      return;

     }

    else

      strncpy(pathname, temp, strlen(temp)-1);

      

      /* switch to Binary mode */

      SendControlCommand("TYPE","I");

      GetReplyMsg();


      if(isPassive() ==0)

      {

          ServerPort =  passive();

          if(ServerPort >0)

               FillServerAddr(ServerIP, ServerPort, &Ftp_Server_data_addr);

          SendControlCommand("RETR", pathname);

          CreateDataConnection();

          data_soc = sockfd_data;

      }

      else

      {


          lis_soc = ftp_asv_connect();


          SendControlCommand("RETR", pathname);

         

          data_soc  = accept(lis_soc,(struct sockaddr * )&local_host,(socklen_t*)&set);


          if(data_soc  == -1)

          {

              printf("Sorry ,you can't use PORT mode,there is something wrong when the server connect to this\n");

              return ;

          }

      }


      GetReplyMsg();

      if(strrchr(pathname,'/') ==NULL){

            newfd = open(pathname, O_WRONLY|O_CREAT,0644);

      }

      else{

            newfd = open(strrchr(pathname,'/')+1, O_WRONLY|O_CREAT,0644);

      }


      if(newfd <0)

        printf("Error: can't open file!");


      else

      {

          for(i =0; i <5 ; ++i)

          {

              if(soc_set[i].soc == -1)

                  break;

          }


          if(i ==5)

          {

              printf("you can't connect to server more than 5\n");

              close(sockfd_data);

          }


          soc_set[i].soc = data_soc;

          soc_set[i].type = get;

          soc_set[i].handle = newfd;

      }


}



void FTP_CMD_UPLOAD(void)

{

    char pathname[MAX_FILE_NAME];

    char filename[MAX_FILE_NAME];

    char temp[MAX_FILE_NAME];

    int newfd;

    int res;

    int Counter;

    int data_soc;

    int i =0;

    int result;

    int lis_soc;

    int set =sizeof(local_host);

    printf("Input file name to upload:");

    fgets(temp,sizeof(temp),stdin);

      if(pathname[0]=='\n')

      {

      printf("please input the file name!");

      return;

     }

    else

      strncpy(pathname, temp, strlen(temp)-1);

      

       SendControlCommand("TYPE","I");

      GetReplyMsg();



      if(isPassive()  ==0)

      {

          ServerPort =  passive();

          if(ServerPort >0)

               FillServerAddr(ServerIP, ServerPort, &Ftp_Server_data_addr);

          SendControlCommand("STOR", pathname);

          CreateDataConnection();

          data_soc = sockfd_data;

      }

      else

      {


          lis_soc = ftp_asv_connect();


          SendControlCommand("STOR", pathname);

         

          data_soc  = accept(lis_soc,(struct sockaddr * )&local_host,(socklen_t*)&set);


          if(data_soc  == -1)

          {

              printf("Sorry ,you can't use PORT mode,there is something wrong when the server connect to this\n");

              return ;

          }

      }


      GetReplyMsg();

      newfd = open(pathname, O_RDONLY);

      if(newfd <0)

        printf("Error: can't open file!");

      else

        {

            Counter = 0;

            memset(DataBuffer, 0, MAX_BUF_LEN);

            while((res=read(newfd, DataBuffer, MAX_BUF_LEN)) >0)

            {

                  write(data_soc, DataBuffer, res);

                  Counter += res;

            }

            printf("%d bytes send\n", Counter);

            close(data_soc);

        }  

}


void GetInputCmd(char* cmd)                   

{

  char buf[MAX_BUF_LEN];

    fgets(buf,sizeof(buf),stdin);

    if(buf[0]=='\n')

        strncpy(cmd,"?",1);

    else

        strncpy(cmd,buf,strlen(buf)-1);

}




int find_maxfd(int  st)

{

    int max_fd = st;

    int i =0;

    for(i =0; i <5; ++i)

    {

        if(soc_set[i].soc != -1)

        {

            if(soc_set[i].soc > max_fd)

                max_fd = soc_set[i].soc;

        }

    }


    return max_fd;

}


//显示帮助命令

void  showhelp()

{

    printf("   start:         Connect to ftp server.\n");

    printf("   ls:            List files in current directory.\n");

    printf("   cd:            Change current directory.\n");

    printf("   get:           Get a file from server.\n");

    printf("  put:           Put a file onto server.\n");

    printf("  quit:          Goodbye and exit.\n");

}



void deal_user_cmd(char * command)

{

    if(strcmp(command,"start") ==0)

    {

      FTP_CMD_START();

    }

    elseif(strcmp(command,"cd") ==0)

    {

      FTP_CMD_CWD();

    }

    elseif(strcmp(command,"ls") ==0)

    {

      FTP_CMD_LIST();

    }

    elseif(strcmp(command,"get") ==0)

    {

      FTP_CMD_DOWNLOAD();

    }

    elseif(strcmp(command,"put") ==0)

    {

      FTP_CMD_UPLOAD();

    }

    elseif(strcmp(command,"quit") ==0)

    {

      FTP_CMD_QUIT();

    }

    elseif(strcmp(command,"?") ==0)

    {

      showhelp();

    }


}


int  ftp_usr_cmd()

{

     char command[40];

     int  i =0;

     int  result;

     int  Counter =0;

     int  res =0;

     showhelp();


     while(1)

     {


        memset(command,0,strlen(command));


        FD_ZERO(&infds);

    

        FD_SET(fileno(stdin),&infds);                  //将标准收入放入监听集合中去


        


        for(i =0; i <5; ++i)

        {

            if(soc_set[i].soc != -1)

            {

                FD_SET(soc_set[i].soc,&infds);

            }

        }

        

        int  maxfd  =  find_maxfd(fileno(stdin));


        if(select(maxfd +1,&infds,NULL,NULL,NULL) == -1)

        {

            printf("call the select fail\n");

            return -1;

        }

        

        //查看标准输入是否会有输入发生

        if(FD_ISSET(fileno(stdin),&infds))

        {

             GetInputCmd(command);

             deal_user_cmd(command);


        }


        for(i =0; i <5; ++i)

        {

             if(soc_set[i].soc == -1)

                continue;

             if(FD_ISSET(soc_set[i].soc,&infds))

             {

                if(soc_set[i].soc == sockfd_ctrl)

                    GetReplyMsg();


                elseif(soc_set[i].type == list) 

                {


                    printf("Recving data! please wait....\n");     

                    result = read(soc_set[i].soc, DataBuffer, MAX_BUF_LEN);

                    printf("%s", DataBuffer);

                    close(soc_set[i].soc);


                    soc_set[i].soc = -1;

                    soc_set[i].type = -1;

                }

                elseif(soc_set[i].type == get)

                {

                    Counter = 0;

                    memset(DataBuffer, 0, MAX_BUF_LEN);

                    while((res=read(soc_set[i].soc, DataBuffer, MAX_BUF_LEN)) >0)

                    {

                         write(soc_set[i].handle, DataBuffer, res);

                         Counter += res;

                    }

                    printf("%d bytes received\n", Counter);

                    close(soc_set[i].soc); 


                    soc_set[i].soc = -1;

                    soc_set[i].type = -1;

                }

             }

         }    

     }

}



void init_soc()

{

    int i  =0;


    for(i =0; i <5; ++i)

        soc_set[i].soc = -1;

}


//主函数里控制循环等待条件

int  main()

{

    init_soc();

    ftp_usr_cmd();

}



0 0
原创粉丝点击