FTP协议(client)

本文详细介绍了FTP协议的工作原理,包括其在TCP/IP体系中的角色,主动和被动模式的区别,以及如何使用FTP指令进行文件传输、登录和设置,同时展示了编程接口示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.简介

        FTP(File Transfer Protocol)是一种用于文件传输的标准协议,主要作用是在服务器和客户端之间实现文件的传输和共享。FTP 协议运行在 TCP 连接上,保证了文件传输的可靠性。FTP 通常使用两个端口,分别是 20 和 21。其中,21 号端口用于控制连接,客户端通过该端口向服务器发送命令和接收响应;20 号端口用于数据传输,客户端和服务器通过该端口进行文件的上传和下载。
        FTP 协议支持多种模式,包括主动模式(Port 模式)和被动模式(Passive 模式)。在主动模式下,客户端主动打开一个临时端口,服务器接收连接并分配一个临时端口进行数据传输。在被动模式下,服务器主动打开一个临时端口,客户端接收连接并分配一个临时端口进行数据传输。
使用 FTP 协议传输文件需要先连接到 FTP 服务器,然后使用 put 或 get 命令来上传或下载文件。例如,使用 ftp 命令连接到 FTP 服务器后,可以使用 put 命令将本地文件上传到服务器:ftp> put localfile remotefile。同样地,使用 get 命令可以将服务器上的文件下载到本地:ftp> get remotefile localfile。这样就完成了文件传输的过程。

2.TCP协议

       
        TCP/IP协议是一个网络通信协议,它负责在不同的计算机之间进行数据传输。TCP/IP协议是Transmission Control Protocol(TCP)和 Internet Protocol(IP)的组合。其中,TCP 负责发现传输的问题,一旦有问题就会发出重传信号,直到所有数据安全正确的传输到目的地,它提供了面向连接的可靠数据传输服务。而 IP 协议工作在网络层,负责对数据包进行编址和路由,它不负责数据的可靠性。TCP/IP 分层模型中,TCP 和 UDP 是传输层协议,IP 协议是网络层协议。TCP/IP 协议是互联网中最基本的通信协议。

        

3.FTP协议中的指令

        连接 FTP 服务器:ftp [主机名]
        显示 FTP 服务器上的目录内容:ls
        进入 FTP 服务器上的目录:cd [目录名]
        获取服务器上的文件:get [文件名]
        下载文件:retr [文件名]
        上传文件:put [文件名]
        删除服务器上的文件:delete [文件名]
        重命名服务器上的文件:rename [原文件名] [新文件名]
        创建新目录:md [目录名]
        删除服务器上的目录:rmd [目录名]
        退出 FTP:quit
        隐藏 FTP 服务器上的文件:mask [文件名]
        显示 FTP 服务器上的文件属性:attr [文件名]
        设置 FTP 服务器的时间和日期:set [时间日期]

4.一些接口的实现

        1.连接ftp服务器,ftp默认端口号21

int ftp::ftp_connect(const char* ip)
{
    int ftp_port = 21;
    
    if (WSAStartup(MAKEWORD(2, 2), &Ws)!=0){
        cout<<"create socket failed ::"<<GetLastError()<<endl;
        return 0;
    }
    m_ctrl_socket = socket(AF_INET, SOCK_STREAM, 0);
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(ip);
    server_addr.sin_port = htons(ftp_port);

    memset(server_addr.sin_zero, 0x00, 8);


    if (connect(m_ctrl_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
        cout << "connect error" << endl;
    }
    else {
        cout << "connect success" << endl;
    }

    //登录ftp

    memset(cmd_send, 0x00, sizeof(cmd_send));

 
    return 0;
}

        2.登录ftp服务器

int ftp::ftp_login(char* user, char* password)
{
    memset(cmd_send,0x00,sizeof(cmd_send));
    sprintf(cmd_send,"USER %s\r\n",user);
    ftp_sendcmd(cmd_send, sizeof(cmd_send));

    memset(cmd_send, 0x00, sizeof(cmd_send));
    sprintf(cmd_send, "PASS %s\r\n", password);
    ftp_sendcmd(cmd_send, sizeof(cmd_send));
    return 0;
}


        3.发送命令

int ftp::ftp_sendcmd(char* cmd,int cmd_length)
{
    int ret = send(m_ctrl_socket,cmd_send,cmd_length,0);
    if (ret == -1) {
        cout << "send cmd fail   " << cmd << endl;
        return -1;
    }
    else {
        cout << "send cmd success   " << cmd << endl;
        return 0;
    }
}


        4.显示当前目录    

int ftp::ftp_directory(char* buff)
{
    memset(cmd_send, 0x00, sizeof(cmd_send));

    strcpy(cmd_send,"PWD\r\n");

    ftp_sendcmd(cmd_send,sizeof(cmd_send));

    return 0;
}


        5.列出目录的所有文件

int ftp::ftp_list(char* dir)
{
    //设置被动模式
    memset(cmd_send, 0x00, sizeof(cmd_send));
    memset(cmd_recv, 0x00, sizeof(cmd_send));
    strcpy(cmd_send, "PASV\r\n");
    ftp_sendcmd(cmd_send, sizeof(cmd_send));
    recv(m_ctrl_socket, cmd_recv, sizeof(cmd_recv), 0);

    Sleep(100);
    if (strncmp(cmd_recv, "220", 3) != 0) {
        cout << "PASV fail" << endl;
        return -1;
    }
    else {
        cout << "PASV success" << endl;
    }

    memset(cmd_send, 0x00, sizeof(cmd_send));
    sprintf(cmd_send, "NLST %s\r\n", dir);
    if (ftp_sendcmd(cmd_send, sizeof(cmd_send))==-1) {
        return -1;
    }

    char rec_buf[256];
    int len = 0;
    while (len = recv(m_data_socket, rec_buf, 256, 0)) {
        rec_buf[len] = '\0';
        cout << "read len:" << len << "data:" << rec_buf << endl;
    }
    vector<std::string> list;


    return 0;
}


        6.ftp上传文件

int ftp::ftp_upload(char* localfile, char* path, char*filename)
{
    //设置被动模式
    memset(cmd_send, 0x00, sizeof(cmd_send));
    memset(cmd_recv, 0x00, sizeof(cmd_send));
    strcpy(cmd_send, "PASV\r\n");
    ftp_sendcmd(cmd_send,sizeof(cmd_send));

    clock_t pasv_start_time, pasv_end_time;
    pasv_start_time = clock();
    //获取返回的端口号

    char* getport = nullptr;
    while (getport == nullptr) {
        recv(m_ctrl_socket, cmd_recv, sizeof(cmd_recv), 0);
        getport = strchr(cmd_recv, '(');
        pasv_end_time = clock();
        if (strncmp(cmd_recv, "220", 3) != 0) {
            cout << "PASV fail" << endl;
            if (pasv_end_time - pasv_start_time > 100) {
                cout << "接受超时,程序退出!!!" << endl;
                return -1;
            }
        }
        else {
            cout << "PASV success" << endl;
        }
    }

    int pa, pb, data_port;
    if (sscanf(getport, "(172,20,10,200,%d,%d", &pa, &pb) == -1) {
        cout << "sscanf " << pa << " " << pb << "error" << endl;
    }
    data_port = pa * 256 + pb;


    m_data_socket = socket(AF_INET,SOCK_STREAM,0);

    //建立传数据通道连接
    struct sockaddr_in send_addr;
    send_addr.sin_family = AF_INET;
    send_addr.sin_addr.s_addr = inet_addr("172.20.10.200");
    send_addr.sin_port = htons(data_port);//30312

    if (connect(m_data_socket, (struct sockaddr*)&send_addr, sizeof(send_addr)) == SOCKET_ERROR) {
        cout << "connect error" << endl;
        closesocket(m_data_socket);
        return -1;
    }
    else {
        cout << "connect success" << endl;
    }

    memset(cmd_recv, 0x00, sizeof(cmd_send));
    memset(cmd_send, 0x00, sizeof(cmd_send));
    sprintf(cmd_send, "STOR %s%s\r\n", path,filename);
    ftp_sendcmd(cmd_send, sizeof(cmd_send));

    recv(m_ctrl_socket, cmd_recv, sizeof(cmd_recv), 0);
    Sleep(100);
    if (strncmp(cmd_recv, "150", 3) != 0) {
        cout << "STOR fail" << endl;
        return -1;
    }
    else {
        cout << "STOR success" << endl;
    }

    ifstream file;

    char sendbuf[16384] = { '\0' };

    file.open(localfile, ios::binary);
    if (!file.is_open()) {
        cout << "fail open file" << endl;
        return 0;
    }
    else {
        file.seekg(0, file.end);//设置输入文件流的文件流指针位置
        int size = file.tellg();
        file.seekg(0, file.beg);//设置输入文件流的文件流指针位置
        file.read(sendbuf, size);
        
        if (send(m_data_socket, sendbuf, size, 0) < 0) {
             cout << "send file fail    " << sendbuf << endl;
              return -1;
           }else {
           cout << "send file success    " << sendbuf << endl;
        }
      
    }

    file.close();

    closesocket(m_data_socket);

    return 0;
}


        7.ftp下载文件

int ftp::ftp_download(char* remotefile, char* localfile)
{
    memset(cmd_send, 0x00, sizeof(cmd_send));
    strcpy(cmd_send,"PASV\r\n");
    if (ftp_sendcmd(cmd_send,sizeof(cmd_send)) == -1)
        return -1;

    clock_t pasv_start_time, pasv_end_time;
    pasv_start_time = clock();
    //获取返回的端口号
    int pa, pb, data_port;
    char* getport = nullptr;
    while (getport == nullptr) {
        recv(m_ctrl_socket, cmd_recv, sizeof(cmd_recv), 0);
        getport = strchr(cmd_recv, '(');
        pasv_end_time = clock();
        if (strncmp(cmd_recv, "220", 3) != 0) {
            cout << "PASV fail" << endl;
            if (pasv_end_time - pasv_start_time > 100) {
                cout << "接受超时,程序退出!!!" << endl;
                return -1;
            }
        }
        else {
            cout << "PASV success" << endl;
        }
    }


    if (sscanf(getport, "(172,20,10,200,%d,%d", &pa, &pb) < 0) {
        cout << "sscanf " << pa << " " << pb << "error" << endl;
    }
    data_port = pa * 256 + pb;

    m_data_socket = socket(AF_INET, SOCK_STREAM, 0);

    //建立传数据通道连接
    struct sockaddr_in send_addr;
    send_addr.sin_family = AF_INET;
    send_addr.sin_addr.s_addr = inet_addr("172.20.10.200");
    send_addr.sin_port = htons(data_port);//30312

    if (connect(m_data_socket, (struct sockaddr*)&send_addr, sizeof(send_addr)) == SOCKET_ERROR) {
        cout << "connect error" << endl;
        closesocket(m_data_socket);
        return -1;
    }
    else {
        cout << "connect success" << endl;
    }

    memset(cmd_send, 0x00, sizeof(cmd_send));
    sprintf(cmd_send, "RETR %s\r\n",remotefile);
    if (ftp_sendcmd(cmd_send, sizeof(cmd_send)) == -1)
        return -1;

    /**************************读取文件**************************************/


    char rec_buf[1024] = { '\0' };


    if (recv(m_data_socket, rec_buf, sizeof(rec_buf), 0) < 0) {
        cout << "receive file fail    " << rec_buf << endl;
        return -1;
    }
    else {
        cout << "receive file success    " << rec_buf << endl;
        fstream outfile;
        outfile.open(localfile);
        outfile << rec_buf << endl;
        outfile.close();
}
    
    closesocket(m_data_socket);

    return 0;

}

8.关闭连接

int ftp::ftp_close()
{
    memset(cmd_send, 0x00, sizeof(cmd_send));
    strcpy(cmd_send, "QUIT\r\n");
    if (ftp_sendcmd(cmd_send, sizeof(cmd_send)) == -1)
        return -1;
    closesocket(m_ctrl_socket);
    closesocket(m_data_socket);
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值