文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

FTP客户端c代码功能实现

2023-09-24 09:37

关注

现在市面上有很多免费的FTP软件:如FileZilla ,那如果想自己在代码中实现与ftp服务器的上传下载文件该如何实现那? 

本质上ftp协议就是TCP基础上建立的一种协议,具体如下。

FTP 概述

文件传输协议(FTP)作为网络共享文件的传输协议,在网络应用软件中具有广泛的应用。FTP的目标是提高文件的共享性和可靠高效地传送数据。

在传输文件时,FTP 客户端程序先与服务器建立连接,然后向服务器发送命令。服务器收到命令后给予响应,并执行命令。FTP 协议与操作系统无关,任何操作系统上的程序只要符合 FTP 协议,就可以相互传输数据。本文主要基于 LINUX 平台,对 FTP 客户端的实现原理进行详尽的解释并阐述如何使用 C 语言编写一个简单的 FTP 客户端。

FTP 协议

相比其他协议,如 HTTP 协议,FTP 协议要复杂一些。与一般的 C/S 应用不同点在于一般的C/S 应用程序一般只会建立一个 Socket 连接,这个连接同时处理服务器端和客户端的连接命令和数据传输。而FTP协议中将命令与数据分开传送的方法提高了效率。

FTP 使用 2 个端口,一个数据端口和一个命令端口(也叫做控制端口)。这两个端口一般是21 (命令端口)和 20 (数据端口)。控制 Socket 用来传送命令,数据 Socket 是用于传送数据。每一个 FTP 命令发送之后,FTP 服务器都会返回一个字符串,其中包括一个响应代码和一些说明信息。其中的返回码主要是用于判断命令是否被成功执行了。

命令端口

一般来说,客户端有一个 Socket 用来连接 FTP 服务器的相关端口,它负责 FTP 命令的发送和接收返回的响应信息。一些操作如“登录”、“改变目录”、“删除文件”,依靠这个连接发送命令就可完成。

数据端口

对于有数据传输的操作,主要是显示目录列表,上传、下载文件,我们需要依靠另一个 Socket来完成。

如果使用被动模式,通常服务器端会返回一个端口号。客户端需要用另开一个 Socket 来连接这个端口,然后我们可根据操作来发送命令,数据会通过新开的一个端口传输。

如果使用主动模式,通常客户端会发送一个端口号给服务器端,并在这个端口监听。服务器需要连接到客户端开启的这个数据端口,并进行数据的传输。

下面对 FTP 的主动模式和被动模式做一个简单的介绍。

主动模式 (PORT)

主动模式下,客户端随机打开一个大于 1024 的端口向服务器的命令端口 P,即 21 端口,发起连接,同时开放N +1 端口监听,并向服务器发出 “port N+1” 命令,由服务器从它自己的数据端口 (20) 主动连接到客户端指定的数据端口 (N+1)。

FTP 的客户端只是告诉服务器自己的端口号,让服务器来连接客户端指定的端口。对于客户端的防火墙来说,这是从外部到内部的连接,可能会被阻塞。

被动模式 (PASV)

为了解决服务器发起到客户的连接问题,有了另一种 FTP 连接方式,即被动方式。命令连接和数据连接都由客户端发起,这样就解决了从服务器到客户端的数据端口的连接被防火墙过滤的问题。

被动模式下,当开启一个 FTP 连接时,客户端打开两个任意的本地端口 (N > 1024 和 N+1) 。

第一个端口连接服务器的 21 端口,提交 PASV 命令。然后,服务器会开启一个任意的端口 (P > 1024 ),返回如“227 entering passive mode (127,0,0,1,4,18)”。 它返回了 227 开头的信息,在括号中有以逗号隔开的六个数字,前四个指服务器的地址,最后两个,将倒数第二个乘 256 再加上最后一个数字,这就是 FTP 服务器开放的用来进行数据传输的端口。如得到 227 entering passive mode (h1,h2,h3,h4,p1,p2),那么端口号是 p1*256+p2,ip 地址为h1.h2.h3.h4。这意味着在服务器上有一个端口被开放。客户端收到命令取得端口号之后, 会通过 N+1 号端口连接服务器的端口 P,然后在两个端口之间进行数据传输。

主要用到的 FTP 命令

FTP 每个命令都有 3 到 4 个字母组成,命令后面跟参数,用空格分开。每个命令都以 "\r\n"结束。

要下载或上传一个文件,首先要登入 FTP 服务器,然后发送命令,最后退出。这个过程中,主要用到的命令有 USER、PASS、SIZE、REST、CWD、RETR、PASV、PORT、QUIT。

USER: 指定用户名。通常是控制连接后第一个发出的命令。“USER gaoleyi\r\n”: 用户名为gaoleyi 登录。

PASS: 指定用户密码。该命令紧跟 USER 命令后。“PASS gaoleyi\r\n”:密码为 gaoleyi。

SIZE: 从服务器上返回指定文件的大小。“SIZE file.txt\r\n”:如果 file.txt 文件存在,则返回该文件的大小。

CWD: 改变工作目录。如:“CWD dirname\r\n”。

PASV: 让服务器在数据端口监听,进入被动模式。如:“PASV\r\n”。

PORT: 告诉 FTP 服务器客户端监听的端口号,让 FTP 服务器采用主动模式连接客户端。如:“PORT h1,h2,h3,h4,p1,p2”。

RETR: 下载文件。“RETR file.txt \r\n”:下载文件 file.txt。

STOR: 上传文件。“STOR file.txt\r\n”:上传文件 file.txt。

REST: 该命令并不传送文件,而是略过指定点后的数据。此命令后应该跟其它要求文件传输的 FTP 命令。“REST 100\r\n”:重新指定文件传送的偏移量为 100 字节。

QUIT: 关闭与服务器的连接。

FTP 响应码

客户端发送 FTP 命令后,服务器返回响应码。

响应码用三位数字编码表示:

第一个数字给出了命令状态的一般性指示,比如响应成功、失败或不完整。

第二个数字是响应类型的分类,如 2 代表跟连接有关的响应,3 代表用户认证。

第三个数字提供了更加详细的信息。

第一个数字的含义如下:

1 表示服务器正确接收信息,还未处理。

2 表示服务器已经正确处理信息。

3 表示服务器正确接收信息,正在处理。

4 表示信息暂时错误。

5 表示信息永久错误。

第二个数字的含义如下:

0 表示语法。

1 表示系统状态和信息。

2 表示连接状态。

3 表示与用户认证有关的信息。

4 表示未定义。

5 表示与文件系统有关的信息。

Socket 编程的几个重要步骤

Socket 客户端编程主要步骤如下:

  1. socket() 创建一个 Socket
  2. connect() 与服务器连接
  3. write() 和 read() 进行会话
  4. close() 关闭 Socket

Socket 服务器端编程主要步骤如下:

  1. socket() 创建一个 Socket
  2. bind()
  3. listen() 监听
  4. accept() 接收连接的请求
  5. write() 和 read() 进行会话
  6. close() 关闭 Socket

实现 FTP 客户端上传下载功能

下面让我们通过一个例子来对 FTP 客户端有一个深入的了解。本文实现的 FTP 客户端有下列功能:

  1. 客户端和 FTP 服务器建立 Socket 连接。
  2. 向服务器发送 USER、PASS 命令登录 FTP 服务器。
  3. 使用 PASV 命令得到服务器监听的端口号,建立数据连接。
  4. 使用 RETR/STOR 命令下载/上传文件。
  5. 在下载完毕后断开数据连接并发送 QUIT 命令退出。

经过测试可以正常上传下载数据,,测试代码如下:

main.c#include #include #include #include "ftp.h"#define FTP_SERVER_IP "XXXXXXXX"#define FTP_SERVER_USER "XXXXX"#define FTP_SERVER_PASS "XXXXXX"#define MAX_BUF_LEN 512typedef struct{    char usr[32];    char passwd[32];    char ser_filepath[512];    char ser_filename[64];    char new_filename[64];    int control_sock;}ftp_client_st; ftp_client_st ftp_st;int main (int argc , char * argv[]){    char str[MAX_BUF_LEN] ={0};    int ret =-1;    //        while(1){        printf("*************\n");        //printf("Please input the ftp server ip: ");        memset(str,0,sizeof(str));        //scanf("%s",str); //从终端获取到服务器ip地址。        strcpy(str,FTP_SERVER_IP);        printf("input fpt server ip:%s\n",str);                memset(&ftp_st,0,sizeof(ftp_client_st));         ftp_st.control_sock = connect_ftp_server(str,FTP_SERVER_PORT);        if(ftp_st.control_sock > 0){            ret = -1;            while(ret < 0){                    strcpy(ftp_st.usr,FTP_SERVER_USER);                strcpy(ftp_st.passwd,FTP_SERVER_PASS);                printf("input usr:%s passwd:%s\n",ftp_st.usr,ftp_st.passwd);                ret = login_ftp_server(ftp_st.control_sock,ftp_st.usr,ftp_st.passwd);                 if(ret < 0){                        printf("\nUser or Passwd is wrong,input agin");                }                else{                    //打印服务器当前目录和列表                    while(1){                    printf("Get list start:\n");                        //ret = down_file_ftpserver(ftp_st.control_sock,"/","/list_mode",0,0,CMD_LIST);                         ret = down_file_ftpserver(ftp_st.control_sock,"/","../list_passive",1,0,CMD_LIST);                        // down_file_ftpserver(ftp_st.control_sock,"/down_test","list1",0,0,CMD_LIST);                        //printf("\nInput down file dir (Input quit to quit):");                        //memset(ftp_st.ser_filepath,0,sizeof(ftp_st.ser_filepath));                        //scanf("%s",ftp_st.ser_filepath);                     //if(strncmp(ftp_st.ser_filepath,"quit",4) ==0)                        //    goto err0;                     #if 0                          printf("\nInput  down filename (Input quit to quit):");                        memset(ftp_st.ser_filename,0,sizeof(ftp_st.ser_filename));                        scanf("%s",ftp_st.ser_filename);                     if(strncmp(ftp_st.ser_filename,"quit",4) ==0)goto err0;                    printf("\nInput new filename (Input quit to quit):");                        memset(ftp_st.new_filename,0,sizeof(ftp_st.new_filename));                        scanf("%s",ftp_st.new_filename);                     if(strncmp(ftp_st.new_filename,"quit",4) ==0)goto err0;printf("input filename :%s; newfilename:%s; \n",ftp_st.ser_filename,ftp_st.new_filename);                    printf("down file start:\n");                        //ret = down_file_ftpserver(ftp_st.control_sock,ftp_st.ser_filename,ftp_st.new_filename,0,0,CMD_RETR);                        ret = down_file_ftpserver(ftp_st.control_sock,ftp_st.ser_filename,ftp_st.new_filename,0,0,CMD_RETR);                        #endif                        down_file_ftpserver(ftp_st.control_sock,"/down_test/test_ftp.zip","../12.zip",1,0,CMD_RETR);                        up_file_ftpserver(ftp_st.control_sock, "/down_test/12.zip", "../12.zip", 1, 0);                        get_fsize_ftpserver(ftp_st.control_sock, "/down_test/12.zip");                        goto err0;                    }        }            }        }            }err0:        quit_fpt_server(ftp_st.control_sock);    return 0;    }

fpt.c

#include #include #include #include #include #include #include #include #include #include #include #include "ftp.h"#define MAX_BUF 512#define IP_LENGTH   16//正常时服务器回复的响应码#define ACK_USER_NUM "331"#define ACK_PASS_NUM "230"#define ACK_PASV_NUM "227"#define ACK_CWD_NUM  "250"#define ACK_SIZE_NUM "213"#define ACK_RETR_NUM "150" #define ACK_REST_NUM "350"#define ACK_QUIT_NUM "200"#define ACK_LIST_NUM "125"#define ACK_STOR_NUM "150"#define ACK_CONNECT_NUM "220"#define ACK_PORT_NUM "200"typedef struct {    //char szUserName[16];    //char szPassWd[32];    char server_path[128];    char server_filename[64];    char new_filename[128];    int data_sock;    char data_ip[32];    int  data_port;    int client_server_sock;    int file_handle;}FTP_DATA_INFO;static int itoa(int value, char * str, int radix);static int send_cmd(int ctrl_sock,eu_cmd_type typ, const char *val,const char *ack_num);static int enter_passive_mode(int ctrl_sock,char *data_ip, int * data_port);static int enter_active_mode(int ctrl_sock);static int get_data_sock(const char* server_ip,const int port);static int get_active_data_sock(int client_server_sock);static int GetAddr(const char *ifname, char *addr, int flag);static int close_st_info(FTP_DATA_INFO * info);FTP_DATA_INFO server_info;static int GetAddr(const char *ifname, char *addr, int flag){    struct sockaddr_in *sin;    struct ifreq ifr;    int sockfd;    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)    {        printf("socket create error!\n");        return - 1;    }    memset(&ifr, 0, sizeof(ifr));    strncpy(ifr.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ);    if(ioctl(sockfd, flag, &ifr) < 0)    {        close(sockfd);        return - 1;    }    close(sockfd);    if(SIOCGIFHWADDR == flag)    {        memcpy((void *)addr, (const void *)&ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);    }    else    {        sin = (struct sockaddr_in *)&ifr.ifr_ifru.ifru_addr;        snprintf((char *)addr, IP_LENGTH, "%s", inet_ntoa(sin->sin_addr));    }    return 0;}static int itoa(int value, char * str, int radix){ char temp[33];  char *tp = temp;   int i;   unsigned v;   int sign;   char *sp;  int num= 0;  if(radix > 36 || radix < 1)     return 0;   sign = (radix == 10 && value < 0); //十进制负数   if(sign)     v = -value;   else    v = (unsigned)value;   while(v || tp == temp)       //转化操作   {     i = v % radix;     v = v / radix;     if(i < 10)       *tp++ = i + '0';     else      *tp++ = i + 'a' - 10;   }   if(str == 0)     str = (char*)malloc((tp - temp) + sign + 1);   sp = str;   if(sign)   //是负数的话把负号先加入数组     *sp++ = '-';   while(tp > temp)  {    *sp++ = *--tp;    num++;  }  *sp = 0;     return num;}int connect_ftp_server(const char* server_ip,const int port){    int control_sock =-1;    int ret =-1;    struct sockaddr_in server;    char read_buf[MAX_BUF]={0};    struct timeval tv_out;        memset(&server,0,sizeof(struct sockaddr_in));        if(server_ip == NULL){        printf("argc is NULL\n");        return -1;    }    control_sock = socket(AF_INET,SOCK_STREAM,0);    if(control_sock <0){        printf("socket failed\n");        return -1;    }        tv_out.tv_sec =0;    tv_out.tv_usec =500*1000;    setsockopt(control_sock, SOL_SOCKET, SO_RCVTIMEO,&tv_out,sizeof(tv_out));            server.sin_family = AF_INET;    server.sin_port = htons(port);    server.sin_addr.s_addr = inet_addr(server_ip);     ret = connect(control_sock,(struct sockaddr *)&server,sizeof(server));    if(ret < 0){        printf("connect failed\n");        return -1;    }    ret =1;            usleep(100*1000);    ret = read(control_sock,read_buf,sizeof(read_buf));    if(ret < 0){        printf("read error\n");        return -1;    }    printf("%s ret=%d \n",read_buf,ret);    if(strncmp(read_buf,ACK_CONNECT_NUM,3) == 0)     {        printf("Connect ftp ok\n");        return control_sock;    }    else    {        close(control_sock);        return -1;    }}static int get_data_sock(const char* server_ip,const int port){    int data_sock =-1;    int ret =-1;    struct sockaddr_in server;    char read_buf[MAX_BUF]={0};        memset(&server,0,sizeof(struct sockaddr_in));        if(server_ip == NULL){        printf("argc is NULL\n");        return -1;    }    data_sock = socket(AF_INET,SOCK_STREAM,0);    if(data_sock <0){        printf("socket failed\n");        return -1;    }        //int cflags = fcntl(data_sock,F_GETFL,0);    //fcntl(data_sock,F_SETFL,cflags|O_NONBLOCK);        server.sin_family = AF_INET;    server.sin_port = htons(port);    server.sin_addr.s_addr = inet_addr(server_ip);     ret = connect(data_sock,(struct sockaddr *)&server,sizeof(server));    if(ret < 0){        printf("connect failed\n");        return -1;    }        return data_sock;}static int get_active_data_sock(int client_server_sock){    int data_sock =-1;    struct sockaddr_in client_name;    int len;    len = sizeof(client_name);    data_sock = accept(client_server_sock,(struct sockaddr *)&client_name ,&len);    if(data_sock <0)    {        printf("accept failed\n");    }    printf("data_sock = %d\n",data_sock);        return data_sock;}int login_ftp_server(int ctrl_sock,const char *user_name, const char * passwd){    int ret =-1;    if((user_name == NULL) ||(passwd == NULL)){        printf("argc is NULL\n");        return -1;    }        ret = send_cmd(ctrl_sock,CMD_USER,user_name,ACK_USER_NUM);    if(ret < 0){            printf("send_cmd  %d failed \n",CMD_USER);            return -1;    }    ret = send_cmd(ctrl_sock,CMD_PASS,passwd,ACK_PASS_NUM);    if(ret < 0){            printf("send_cmd  %d failed \n",CMD_PASS);            return -1;    }    return 0;}static int send_cmd(int ctrl_sock,eu_cmd_type typ, const char *val,const char *ack_num){    int ret =-1;    char send_buf[MAX_BUF]={0};    char read_buf[MAX_BUF]={0};    char *pos= NULL;    char tmp[64] ={0};    if((typ == CMD_USER) ||(typ == CMD_PASS) || (typ == CMD_CWD)){        if((val == NULL) ||(ack_num == NULL)){            printf("argc is NULL\n");            return -1;        }    }        switch(typ){    case CMD_USER:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"USER %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }        ret = strncmp(read_buf,ack_num,strlen(ack_num));        break;    case CMD_PASS:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"PASS %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }        ret = strncmp(read_buf,ack_num,strlen(ack_num));        break;    case CMD_PASV:         memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"PASV\r\n");        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        break;    case CMD_CWD:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"CWD %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        usleep(500*1000);        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }        ret = strncmp(read_buf,ack_num,strlen(ack_num));        break;    case CMD_QUIT:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"QUIT\r\n");        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        usleep(500*1000);        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }    //    ret = strncmp(read_buf,ack_num,strlen(ack_num));    case CMD_LIST:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"LIST %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        memset(read_buf,0,sizeof(read_buf));        usleep(100*1000);         ret = read(ctrl_sock,read_buf,sizeof(send_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }    //    ret = strncmp(read_buf,ack_num,strlen(ack_num));        break;    case CMD_STOR:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"STOR %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        usleep(50*1000);        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }    //    ret = strncmp(read_buf,ack_num,strlen(ack_num));        break;    case CMD_RETR:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"RETR %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        usleep(50*1000);        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }    //    ret = strncmp(read_buf,ack_num,strlen(ack_num));        break;    case CMD_SIZE_FTP:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"SIZE %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        usleep(50*1000);        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }                pos = strstr(read_buf,ack_num);        if(pos != NULL){            pos += strlen(ack_num) +1;            strcpy(tmp,pos);            ret = atoi(tmp);        }        else{            ret =-1;        }                break;        case CMD_PORT_FTP:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"PORT %s\r\n",val);        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        usleep(50*1000);        memset(read_buf,0,sizeof(read_buf));        ret = read(ctrl_sock,read_buf,sizeof(read_buf));        if(ret < 0){            printf("read failed\n");            return -1;        }        ret = strncmp(read_buf,ack_num,strlen(ack_num));        break;        case CMD_MLSD:        memset(send_buf,0,sizeof(send_buf));        sprintf(send_buf,"MLSD\r\n");        ret = write(ctrl_sock,send_buf,strlen(send_buf));        if(ret < 0){            printf("write failed\n");            return -1;        }        break;    default:break;    }    printf("FTP server ack= %s\n",read_buf);        return ret;}static int enter_active_mode(int ctrl_sock){    int data_sock,server_sock;    struct sockaddr_in name;    struct sockaddr_in client_name,loc_addr;    unsigned short server_port =0;    int ret =-1;    int len =0;    char send_buf[64] ={0};    char ip[20]={0};    unsigned short  ip0,ip1,ip2,ip3,p1,p2;    //char read_buf[128] ={0};    struct timeval tv_out;        tv_out.tv_sec =3;    tv_out.tv_usec =0;      memset(&name,0,sizeof(name));    memset(&client_name,0,sizeof(client_name));        len =sizeof(name);    if(getsockname(ctrl_sock,(struct sockaddr*)&name,&len) == -1)    {        printf("get sock name failed\n");        return -1;    }        sscanf(inet_ntoa(name.sin_addr),"%hu.%hu.%hu.%hu",&ip0,&ip1,&ip2,&ip3);            server_sock = socket(AF_INET,SOCK_STREAM,0);    if(server_sock <0){        printf("get sock failed\n");        return -1;    }        setsockopt(server_sock, SOL_SOCKET, SO_RCVTIMEO,&tv_out,sizeof(tv_out));        name.sin_family = AF_INET;    name.sin_port = 0;    len = sizeof(name);    ret = bind(server_sock,(struct sockaddr *)&name,len);    if(ret < 0){        printf("bind error\n");        goto err0;    }            len = sizeof(loc_addr);    memset(&loc_addr,0,len);    ret = getsockname(server_sock,(struct sockaddr *)&loc_addr,&len);    if(ret < 0)    {        printf("get sock name failed\n");        goto err0;    }    server_port = ntohs(loc_addr.sin_port);     p1 = server_port/256;    p2 = server_port%256;    ret = listen(server_sock,10);    if(ret < 0)    {        printf("listen error\n");        goto err0;    }        #if 0        &ip0 = strtok(ip,".");    &ip1 = strtok(NULL,".");    &ip2 = strtok(NULL,".");    &ip3 = strtok(NULL,".");#endif    sprintf(send_buf,"%hu,%hu,%hu,%hu,%hu,%hu",ip0,ip1,ip2,ip3,p1,p2);    printf("send_buf =%s server_port=%d\n",send_buf,server_port);    ret = send_cmd(ctrl_sock,CMD_PORT_FTP, send_buf,ACK_PORT_NUM);    if(ret < 0){        printf("Send PORT failed\n");        goto err0;    }    return server_sock;err0:    close(server_sock);    return -1;}static int enter_passive_mode(int ctrl_sock,char *data_ip, int * data_port){    int ret =-1;    char read_buf[MAX_BUF]={0};    char tmp_buf[64]={0};    unsigned char ip1,ip2,ip3,ip4,port1,port2;    //char *tmp;    if((data_ip == NULL) ||(data_port == NULL)){        printf("argc is NULL\n");        return -1;    }    ret = send_cmd(ctrl_sock,CMD_PASV,NULL,NULL);    if(ret < 0){            printf("send_cmd  %d failed \n",CMD_PASV);            return -1;    }    usleep(100*1000);    ret = read(ctrl_sock,read_buf,sizeof(read_buf));    if(ret < 0){        printf("read failed\n");        return -1;    }    printf("rev =%d: %s\n",ret,read_buf);    if(strstr(read_buf,ACK_PASV_NUM) != NULL){                sscanf(strchr(read_buf,'(')+1,"%hhu,%hhu,%hhu,%hhu,%hhu,%hhu",&ip1,&ip2,&ip3,&ip4,&port1,&port2);        //printf("ip1=%d,ip2=%d,ip3=%d,ip4=%d,port1 =%d ,port2 = %d\n",ip1,ip2,ip3,ip4,port1,port2);                //snprintf(data_ip,sizeof(data_ip),"%hhu,%hhu,%hhu,%hhu",ip1,ip2,ip3,ip4);        //memset(data_ip,0,sizeof(data_ip));        //snprintf(data_ip,sizeof(data_ip),"%d.%d.%d.%d",ip1,ip2,ip3,ip4);        //printf("data_ip = %s\n",data_ip);        memset(data_ip,0,sizeof(data_ip));        memset(tmp_buf,0,sizeof(tmp_buf));        itoa(ip1,tmp_buf,10);        strcat(data_ip,tmp_buf);        strcat(data_ip,".");                memset(tmp_buf,0,sizeof(tmp_buf));        itoa(ip2,tmp_buf,10);        strcat(data_ip,tmp_buf);        strcat(data_ip,".");        memset(tmp_buf,0,sizeof(tmp_buf));        itoa(ip3,tmp_buf,10);        strcat(data_ip,tmp_buf);        strcat(data_ip,".");        memset(tmp_buf,0,sizeof(tmp_buf));        itoa(ip4,tmp_buf,10);        strcat(data_ip,tmp_buf);        //printf("data_ip1 = %s\n",data_ip);            *data_port = port1*256+port2;            }    return 0;}int down_file_ftpserver(int ctrl_sock, char *server_filepath_name,const  char *newfilename,int connect_mode,int offset,eu_cmd_type typ){        int ret =-1,file_size=0;    char rec_buf[2048] ={0};    char stri[128]={0};    int read_size =0;    char * pos =NULL;    char *tmp = NULL;    int flags =O_CREAT|O_RDWR|O_TRUNC;;        close_st_info(&server_info);    if(server_filepath_name == NULL  || newfilename == NULL){        printf("argc is NULL\n");        return -1;    }            tmp = server_filepath_name;    if(tmp != NULL){        while(tmp != NULL){                tmp = strstr(tmp,"/");        //    printf("tmp =%x :%s\n",tmp,tmp);            if(tmp != NULL){                pos = tmp;                tmp++;             }        }        if(pos !=NULL){            strncpy(server_info.server_path,server_filepath_name,pos-server_filepath_name+1);            strcpy(server_info.server_filename,pos+1);        }        else{                strcpy(server_info.server_filename,server_filepath_name);        }    }    printf("server path = %s ;file name =%s\n",server_info.server_path,server_info.server_filename);    if((typ !=CMD_RETR) && (typ !=CMD_LIST)){        printf("typ value is not CMD_RETR or CMD_LIST\n");        return -1;        }    if(connect_mode){             server_info.client_server_sock =enter_active_mode(ctrl_sock);        if(server_info.client_server_sock< 0)        {            printf("get data_scok failed\n");            return -1;        }    }else{         ret = enter_passive_mode(ctrl_sock,server_info.data_ip, &server_info.data_port);        if(ret < 0){                printf("set passive mode failed\n");                return -1;        }        printf("server_info.data_ip =%s, data_port =%d \n",server_info.data_ip,server_info.data_port);        server_info.data_sock = get_data_sock(server_info.data_ip,server_info.data_port);        if(server_info.data_sock < 0){            printf("get data sock failed\n");            return -1;        }    }          if(strlen(server_info.server_path) !=0)       {         ret =  send_cmd(ctrl_sock,CMD_CWD,server_info.server_path,ACK_CWD_NUM);         if(ret < 0){                printf("set passive mode failed\n");                goto err0;         }      }           if(typ ==CMD_RETR){                  if(offset >0){                     flags =O_CREAT|O_RDWR|O_APPEND;                   itoa(offset,stri,10);             ret =    send_cmd(ctrl_sock,CMD_REST,stri,ACK_REST_NUM);              if(ret < 0){                     printf("set file offsize failed\n");                     goto err0;              }           }         ret =  send_cmd(ctrl_sock,CMD_RETR,server_info.server_filename,ACK_RETR_NUM);         if(ret < 0){                printf("send RETR failed\n");                goto err0;         }      }    else if(typ ==CMD_LIST){         ret =  send_cmd(ctrl_sock,CMD_LIST,server_filepath_name,ACK_LIST_NUM);         if(ret < 0){                printf("send LIST failed\n");                goto err0;         }      }    if(connect_mode){        server_info.data_sock= get_active_data_sock(server_info.client_server_sock);        if(server_info.data_sock <0)        {            printf("accept failed\n");            goto err0;        }    }      server_info.file_handle = open(newfilename,flags,0766);     if(server_info.file_handle < 0){        printf("open file failed\n");            goto err0;     }     if(offset >0){         lseek(server_info.file_handle,offset, SEEK_SET);         read_size += offset;     }          for(;;){         memset(rec_buf,0,sizeof(rec_buf));                ret = recv(server_info.data_sock,rec_buf,sizeof(rec_buf),0);         if(ret < 0)         {            printf("Read error\n");            goto err1;        }        else if(ret == 0)        {            ret = read_size;            goto err1;        }        else if(ret >0)        {            read_size += ret;            ret = write(server_info.file_handle,rec_buf,ret);            if(ret < 0)            {                printf("Write error\n");                goto err1;            }            //printf("read_buf =%s\n",rec_buf);        }          }    err1:    if(server_info.file_handle >0)        close(server_info.file_handle);err0:    if(server_info.client_server_sock > 0)        close(server_info.client_server_sock);    if(server_info.data_sock > 0)        close(server_info.data_sock);    memset(rec_buf,0,sizeof(rec_buf));        read(ctrl_sock,rec_buf,sizeof(rec_buf));     printf("%s \n Download file end!!\n",rec_buf);        return ret;    }int up_file_ftpserver(int ctrl_sock, char *server_filepath_name,        const  char *srcfilename,int connect_mode,int offset){    int ret =-1,file_size=0;    int file_handle =0;    char rec_buf[2048] ={0};    int read_size =0;    char stri[128]={0};    char *tmp = NULL;    char * pos =NULL;    close_st_info(&server_info);    if((server_filepath_name == NULL) ||(srcfilename == NULL)){        printf("argc is NULL\n");        return -1;    }            tmp = server_filepath_name;    if(tmp != NULL){        while(tmp != NULL){                tmp = strstr(tmp,"/");        //    printf("tmp =%x :%s\n",tmp,tmp);            if(tmp != NULL){                pos = tmp;                tmp++;             }        }        if(pos !=NULL){            strncpy(server_info.server_path,server_filepath_name,pos-server_filepath_name+1);            strcpy(server_info.server_filename,pos+1);        }        else{                strcpy(server_info.server_filename,server_filepath_name);        }    }    printf("server path = %s ;file name =%s\n",server_info.server_path,server_info.server_filename);    if(connect_mode){                 server_info.client_server_sock =enter_active_mode(ctrl_sock);        if(server_info.client_server_sock <= 0)        {            printf("get data_scok failed\n");            return -1;        }            }else{         ret = enter_passive_mode(ctrl_sock,server_info.data_ip, &server_info.data_port);        if(ret < 0){                printf("set passive mode failed\n");                return -1;        }        printf("server_info.data_ip =%s, data_port =%d\n",server_info.data_ip,server_info.data_port);        server_info.data_sock =  get_data_sock(server_info.data_ip,server_info.data_port);        if(server_info.data_sock < 0){            printf("get data sock failed\n");            return -1;        }    }            if(strlen(server_info.server_path) !=0)        {          ret =  send_cmd(ctrl_sock,CMD_CWD, server_info.server_path,ACK_CWD_NUM);          if(ret < 0){                 printf("set passive mode failed\n");                 goto err0;          }       }          if(offset >0){          itoa(offset,stri,10);         ret =    send_cmd(ctrl_sock,CMD_REST,stri,ACK_REST_NUM);          if(ret < 0){                 printf("set file offsize failed\n");                 goto err0;          }       }         ret =  send_cmd(ctrl_sock,CMD_STOR,server_info.server_filename,ACK_STOR_NUM);     if(ret < 0){            printf("send STOR failed\n");            goto err0;     }           if(connect_mode){        server_info.data_sock= get_active_data_sock(server_info.client_server_sock);        if(server_info.data_sock <0)        {            printf("accept failed\n");            goto err0;        }    }                server_info.file_handle = open(srcfilename,O_RDONLY);     if(server_info.file_handle < 0){        printf("open file failed\n");            goto err0;     }     if(offset >0){         lseek(server_info.file_handle,offset, SEEK_SET);         read_size += offset;     }          for(;;){         memset(rec_buf,0,sizeof(rec_buf));        ret = read(server_info.file_handle,rec_buf,sizeof(rec_buf));         if(ret < 0)         {             printf("read file error\n");            goto err1;        }        else if(ret == 0)        {            ret = read_size;            goto err1;        }        else if(ret >0)        {            //printf("read_buf =%s\n",rec_buf);                        ret = write(server_info.data_sock,rec_buf,ret);            if(ret < 0)            {                    printf("Write failed\n");                    goto err1;                }else{                  read_size += ret;                // lseek(file_handle,read_size, SEEK_SET);            }            }     }err1:    if(server_info.file_handle >0)        close(server_info.file_handle);err0:    if(server_info.client_server_sock > 0)        close(server_info.client_server_sock);    if(server_info.data_sock > 0)        close(server_info.data_sock);    memset(rec_buf,0,sizeof(rec_buf));        read(ctrl_sock,rec_buf,sizeof(rec_buf));     printf("%s\n Up file end!!!\n",rec_buf);        return ret;    }static int close_st_info(FTP_DATA_INFO * info){    if(info == NULL)        return -1;    if(info->file_handle >0)        close(info->file_handle);    if(info->client_server_sock > 0)        close(info->file_handle);    if(info->data_sock > 0)        close(info->file_handle);    memset(info,0,sizeof(FTP_DATA_INFO));    return 0;}int get_fsize_ftpserver(int ctrl_sock, char *server_filepath_name){    int ret =-1;    if(server_filepath_name ==NULL){        printf("argc is null\n");        return -1;    }             ret =  send_cmd(ctrl_sock,CMD_SIZE_FTP,server_filepath_name,ACK_SIZE_NUM);     if(ret < 0){            printf("send SZIE failed\n");            return -1;     }     //printf("file size =%d\n",ret);    return ret;}int quit_fpt_server(int ctrl_sock){    int ret =-1;    close_st_info(&server_info);        ret = send_cmd(ctrl_sock,CMD_QUIT,NULL,ACK_QUIT_NUM);    if(ret < 0)        printf("quit fpt server error\n");    close(ctrl_sock);        return ret;}

fpt.h

#ifndef __FTP_H__#define __FTP_H__#define FTP_SERVER_PORT 21typedef enum{    CMD_USER =0,     CMD_PASS,        CMD_PASV,        CMD_CWD,         CMD_SIZE_FTP,        CMD_RETR,        CMD_REST,          CMD_QUIT,           CMD_LIST,        CMD_STOR,            CMD_PORT_FTP,    CMD_MLSD,     }eu_cmd_type;int connect_ftp_server(const char* server_ip,const int port);int login_ftp_server(int ctrl_sock,const char *user_name, const char * passwd);int down_file_ftpserver(int ctrl_sock, char *server_filepath_name,    const  char *newfilename,int connect_mode,int offset,eu_cmd_type typ);int up_file_ftpserver(int ctrl_sock, char *server_filepath_name,        const  char *srcfilename,int connect_mode,int offset);int get_fsize_ftpserver(int ctrl_sock, char *server_filepath_name);int quit_fpt_server(int ctrl_sock);#endif

遇到的主要问题记录:

  1、实现FTP主动模式的时候,开始的accpet一直无法接收到服务器的连接请求。

后来用wireshark跟踪FileZilla与服务器直接的通信数据才找到问题所在。原来accept要在

必须要在LIST等下载上传命令发送后服务器才会连接过来。

      2、主要一定要关闭掉防火墙

      3、ftp还有一些传送方法类型的选择,本代码中并没有进行设置,后续用到的时候再进行完善。

  4、 代码中接收服务器回复的时候增加了不少延迟。后来我有在sock 上设置接收超时,延迟太多反正感觉不是太好。

   5、最近更换了一个ftp服务器平台时,发现新问题。发现下载后的文件大小变大了。经过对比发现多了很多0D .

从网上查询发现时Linux系统的回车时\n. 而windows系统的回车时\r\n。 所以当ftp 采用ascii方式传播的时候是有着问题的。

解决方法是发送TYPE  I\r\n命令将传输方式设置为二进制传输 。问题解决。

命令及响应码

命令描述
ABOR中断数据连接程序
ACCT 系统特权帐号
ALLO 为服务器上的文件存储器分配字节
APPE 添加文件到服务器同名文件
CDUP 改变服务器上的父目录
CWD 改变服务器上的工作目录
DELE 删除服务器上的指定文件
HELP 返回指定命令信息
LIST 如果是文件名列出文件信息,如果是目录则列出文件列表
MODE 传输模式(S=流模式,B=块模式,C=压缩模式)
MKD 在服务器上建立指定目录
NLST 列出指定目录内容
NOOP无动作,除了来自服务器上的承认
PASS 系统登录密码
PASV请求服务器等待数据连接
PORT
IP 地址和两字节的端口 ID
PWD显示当前工作目录
QUIT从 FTP 服务器上退出登录
REIN重新初始化登录状态连接
REST 由特定偏移量重启文件传递
RETR 从服务器上找回(复制)文件
RMD 在服务器上删除指定目录
RNFR 对旧路径重命名
RNTO 对新路径重命名
SITE 由服务器提供的站点特殊参数
SMNT 挂载指定文件结构
STAT 在当前程序或目录上返回信息
STOR 储存(复制)文件到服务器上
STOU 储存文件到服务器名称上
STRU 数据结构(F=文件,R=记录,P=页面)
SYST返回服务器使用的操作系统
TYPE 数据类型(A=ASCII,E=EBCDIC,I=binary)
USER 系统登录的用户名
响应代码解释说明
110新文件指示器上的重启标记
120服务器准备就绪的时间(分钟数)
125打开数据连接,开始传输
150打开连接
200成功
202命令没有执行
211系统状态回复
212目录状态回复
213文件状态回复
214帮助信息回复
215系统类型回复
220服务就绪
221退出网络
225打开数据连接
226结束数据连接
227进入被动模式(IP 地址、ID 端口)
230登录因特网
250文件行为完成
257路径名建立
331要求密码
332要求帐号
350文件行为暂停
421服务关闭
425无法打开数据连接
426结束连接
450文件不可用
451遇到本地错误
452磁盘空间不足
500无效命令
501错误参数
502命令没有执行
503错误指令序列
504无效命令参数
530未登录网络
532存储文件需要帐号
550文件不可用
551不知道的页类型
552超过存储分配
553文件名不允许

来源地址:https://blog.csdn.net/Gefangenes/article/details/131099451

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-服务器
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯