iis服务器助手广告广告
返回顶部
首页 > 资讯 > 服务器 >FTP客户端c代码功能实现
  • 840
分享到

FTP客户端c代码功能实现

服务器网络linux 2023-09-24 09:09:58 840人浏览 八月长安
摘要

现在市面上有很多免费的FTP软件:如FileZilla ,那如果想自己在代码中实现与ftp服务器的上传下载文件该如何实现那?  本质上ftp协议就是tcp基础上建立的一种协议,具体如下。 FTP 概述 文件传输协议(FTP)作为网络共享文件

现在市面上有很多免费的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

--结束END--

本文标题: FTP客户端c代码功能实现

本文链接: https://www.lsjlt.com/news/416816.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • FTP客户端c代码功能实现
    现在市面上有很多免费的FTP软件:如FileZilla ,那如果想自己在代码中实现与ftp服务器的上传下载文件该如何实现那?  本质上ftp协议就是TCP基础上建立的一种协议,具体如下。 FTP 概述 文件传输协议(FTP)作为网络共享文件...
    99+
    2023-09-24
    服务器 网络 linux
  • C#实现MQTT服务端与客户端通讯功能
    关于MQTT MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上,是为硬件性能低下的远程设...
    99+
    2024-04-02
  • C++实现简单FTP客户端软件开发
    本文实例为大家分享了C++实现简单FTP客户端软件开发的具体实现代码,供大家参考,具体内容如下 题目 简单FTP客户端软件开发(100分)网络环境中的一项基本应用就是将文件从一台计算...
    99+
    2022-11-13
    C++ FTP 客户端
  • C#编写游戏客户端的实现代码
    一、连接客户端原理流程图 二、功能要求 1)连接成功后,可以将服务器发来的消息不停地显示在 listbox 中; 2) 客户端要发给服务器的数据,通过 textbox输入 或者点...
    99+
    2024-04-02
  • C#用websocket实现简易聊天功能(客户端)
    本文实例为大家分享了C#用websocket实现简易聊天功能的具体代码,供大家参考,具体内容如下 前言 使用C#语言进行开发,基于.NET FrameWork4功能包含群聊,和私聊参...
    99+
    2024-04-02
  • C++ 实现高性能HTTP客户端
    目录一、什么是Http Client二、请求的过程1. 创建Http任务2. 填写header并发出3. 处理返回结果三、高性能的基本保证1. 异步调度模式2. 连接复用3. 解锁其...
    99+
    2024-04-02
  • C#如何实现MQTT服务端与客户端通讯功能
    这期内容当中小编将会给大家带来有关C#如何实现MQTT服务端与客户端通讯功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。关于MQTTMQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 2...
    99+
    2023-06-29
  • C++编写的WebSocket服务端客户端实现示例代码
    目录使用过标准的libwebsockets服务端库测试过,主要是短小精悍,相对于libwebsockets不需要依赖zlib和openssl 以及其他库,直接make就可以使用了,l...
    99+
    2024-04-02
  • 怎么在C#中使用MJPEG实现一个客户端功能
    怎么在C#中使用MJPEG实现一个客户端功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。环境:服务端MJPEG服务器使用的是手机的DroidCam,很方便的一个MJPEG服务...
    99+
    2023-06-06
  • nodejs中socket怎么实现服务端和客户端功能
    小编给大家分享一下nodejs中socket怎么实现服务端和客户端功能,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体如下:使用node.js的net模块能很快的开发出基于TCP的服务端...
    99+
    2024-04-02
  • Android客户端中怎么实现RSA加密功能
    Android客户端中怎么实现RSA加密功能,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Android 客户端RSA加密的实现方法针对java后端进行的RSA...
    99+
    2023-05-30
    android rsa
  • Java聊天室之实现客户端群聊功能
    目录一、题目描述二、解题思路三、代码详解一、题目描述 题目实现:不同的客户端之间需要进行通信,一个客户端与其他的多个客户端进行通信,实现群聊功能。 实现一个客户端与其他多个客户端进行...
    99+
    2022-11-13
    Java实现聊天室 Java 聊天室 Java 客户端群聊
  • ​java实现客户端调用的代码怎么写
    下面是一个简单的Java客户端调用示例代码: import java.io.BufferedReader; import java....
    99+
    2023-10-23
    ​java
  • C#WinForm实现自动更新程序之客户端的示例代码
    目录前言开发环境开发工具实现代码实现效果前言 第二步理论上我们该写客户端了,但是,在此之前,需要先介绍下一些必要的方法以及操作。 写代码还是要尽量的保证通用性,以便以后需要的时候可以...
    99+
    2022-11-13
    C# WinForm 自动更新程序 C# WinForm更新程序 C# WinForm
  • Python如何利用IMAP实现邮箱客户端功能
    目录概述什么是IMAP?IMAP和POP有什么区别?如何设置IMAP服务的SSL加密方式?涉及知识点示例效果图核心代码邮箱设置总结概述 在日常工作生活中,都是利用个人或公司的...
    99+
    2024-04-02
  • Java聊天室之实现聊天室客户端功能
    目录一、题目描述二、解题思路三、代码详解一、题目描述 题目实现:实现聊天室客户端。运行程序,用户登录服务器后,可以从用户列表中选择单个用户进行聊天,也可以选择多个用户进行聊天。 二、...
    99+
    2022-11-13
    Java实现聊天室 Java 聊天室 Java 客户端
  • SpringBoot整合WebSocket的客户端和服务端的实现代码
    目录一、项目中服务端的创建二、java充当客户端链接ws1、ws客户端的配置2、配置信息需要在项目启动的时候去启用和链接ws服务3、接收服务端推送的消息进行权限过滤demo4、ws客...
    99+
    2024-04-02
  • Spring Boot集成Sorl搜索客户端的实现代码
    Apache Solr是一个搜索引擎。Spring Boot为solr客户端库及Spring Data Solr提供的基于solr客户端库的抽象提供了基本的配置。Spring Boot提供了一个用于聚集依赖的spring-boot-star...
    99+
    2023-05-30
    spring boot sorl
  • nodejs如何实现TCP服务器端和客户端聊天功能
    这篇文章主要介绍了nodejs如何实现TCP服务器端和客户端聊天功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体如下:服务器端var&...
    99+
    2024-04-02
  • java实现多客户聊天功能
    java 实现多客户端聊天(TCP),供大家参考,具体内容如下 1. 编程思想: 1)、要想实现多客户端聊天,首先需要有多个客户端,而这些客户端需要随时发送消息和接受消息,所以收发消...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作