C++实现ftp客户端


 

#ifndef CLIENT_H_

#define CLIENT_H_

 

#include <sys/socket.h>

#include <unistd.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/ioctl.h>

#include <netinet/in.h>

#include <sys/stat.h>

#include <netdb.h>

#include <errno.h>

#include <arpa/inet.h>

#include <sys/stat.h>

#include <string>

#include <list>

 

 

#define INVALID_SOCKET                -1

#define FTP_API                        int

#define MAX_PATH                    260

#define trace                        printf

 

#define FTP_PARAM_BASE

#define FTP_DEFAULT_PORT            "21"                            //FTP默认端口号

#define FTP_DEFAULT_BUFFER            1024*4                            //FTP下载缓冲默认大小

#define FTP_DEFAULT_PATH            "/mnt/dvs/"                        //FTP默认保存路径

    

#define FTP_COMMAND_BASE            1000

#define FTP_COMMAND_END                FTP_COMMAND_BASE + 30

#define FTP_COMMAND_USERNAME        FTP_COMMAND_BASE + 1            //用户名

#define FTP_COMMAND_PASSWORD        FTP_COMMAND_BASE + 2            //密码

#define FTP_COMMAND_QUIT            FTP_COMMAND_BASE + 3            //退出

#define FTP_COMMAND_CURRENT_PATH    FTP_COMMAND_BASE + 4            // 获取文件路径

#define FTP_COMMAND_TYPE_MODE        FTP_COMMAND_BASE + 5            // 改变传输模式

#define FTP_COMMAND_PSAV_MODE        FTP_COMMAND_BASE + 6            // 被动端口模式

#define FTP_COMMAND_DIR                FTP_COMMAND_BASE + 7            // 获取文件列表

#define FTP_COMMAND_CHANGE_DIRECTORY FTP_COMMAND_BASE + 8            // 改变路径

#define FTP_COMMAND_DELETE_FILE        FTP_COMMAND_BASE + 9            // 删除文件

#define FTP_COMMAND_DELETE_DIRECTORY FTP_COMMAND_BASE + 10            // 删除目录/文件夹

#define FTP_COMMAND_CREATE_DIRECTORY FTP_COMMAND_BASE + 11            // 创建目录/文件夹

#define FTP_COMMAND_RENAME_BEGIN    FTP_COMMAND_BASE  +12            // 开始重命名

#define FTP_COMMAND_RENAME_END      FTP_COMMAND_BASE + 13            // 重命名结束

#define FTP_COMMAND_FILE_SIZE        FTP_COMMAND_BASE + 14            // 获取文件大小

#define FTP_COMMAND_DOWNLOAD_POS    FTP_COMMAND_BASE + 15            // 下载文件从指定位置开始

#define FTP_COMMAND_DOWNLOAD_FILE    FTP_COMMAND_BASE + 16            // 下载文件

#define FTP_COMMAND_UPLOAD_FILE        FTP_COMMAND_BASE + 17            // 上传文件

#define FTP_COMMAND_APPEND_FILE        FTP_COMMAND_BASE + 18            // 追加上载文件    

 

/*          登陆步骤

        login2Server

            |

        inputUserName

            |

        inputPassWord

            |

          具体操作

            |

          quit

*/

 

class CFTPManager 

{

public :

    

    enum type {

        binary = 0x31,

        ascii,

    };

    

    CFTPManager(void);

 

    virtual ~CFTPManager(void);

    

    // ! 登陆服务器

    FTP_API login2Server(const std::string &serverIP);

 

    // !输入用户名

    FTP_API inputUserName(const std::string &userName);

 

    // !输入密码

    FTP_API inputPassWord(const std::string &password);

 

    // !退出FTP

    FTP_API quitServer(void);

 

    // !命令: PWD

    const std::string PWD();

 

    // !设置传输格式 2进制  还是ascii方式传输

    FTP_API setTransferMode(type mode);

 

    // !设置为被动模式

    const std::string Pasv();

 

    // ! 命令: DIR

    const std::string Dir(const std::string &path);

 

    // !命令 : CD

    FTP_API CD(const std::string &path);

 

    // !删除文件

    FTP_API DeleteFile(const std::string &strRemoteFile);

 

    // ! 删除文件夹/目录

    FTP_API DeleteDirectory(const std::string &strRemoteDir);

 

    // ! 创建目录/文件夹

    FTP_API CreateDirectory(const std::string &strRemoteDir);

 

    // !重命名

    FTP_API Rename(const std::string &strRemoteFile, const std::string &strNewFile);

 

    // !获取文件大小

    long getFileLength(const std::string &strRemoteFile);

 

    // !关闭连接

    void Close(int sock);

 

    // 下载文件

    FTP_API Get(const std::string &strRemoteFile, const std::string &strLocalFile);

 

    // 上载文件  支持断电传送方式

    FTP_API Put(const std::string &strRemoteFile, const std::string &strLocalFile);

 

 

private:

    // !合成发送到服务器的命令

    const std::string parseCommand(const unsigned int command, const std::string &strParam);

 

    // ! 建立连接

    FTP_API Connect(int socketfd, const std::string &serverIP, unsigned int nPort);

 

    // ! 返回服务器信息

    const std::string serverResponse(int sockfd);

 

    // !获取服务器数据

    FTP_API getData(int fd, char *strBuf, unsigned long length);

 

    // !发送命令

    FTP_API Send(int fd, const std::string &cmd);

 

    // !发送命令

    FTP_API Send(int fd, const char *cmd, const size_t len);

 

    // !建立数据连接

    FTP_API createDataLink(int data_fd);

 

    // !解析PASV模式返回的字符串获取FTP端口号和FTP服务器IP

    FTP_API ParseString(std::list<std::string> strArray, unsigned long & nPort ,std::string & strServerIp);

 

    // 打开本地文件

    FILE *createLocalFile(const std::string &strLocalFile);

 

    // 下载文件 

    FTP_API downLoad(const std::string &strRemoteFile, const std::string &strLocalFile, const int pos = 0, const unsigned int length = 0);

 

    // 解析返回ftp命令的值

    FTP_API parseResponse(const std::string &str);

 

private:

    //!控制连接套接字

    int        m_cmdSocket;

    

    // !当前用户名

    std::string m_strUserName;

 

    // !当前用户密码

    std::string m_strPassWord;

 

    // !服务器的IP

    std::string m_strServerIP;

 

    // !服务器Port

    unsigned int m_nServerPort;

 

    // !服务器回应信息缓存

    std::string m_strResponse;

 

    // !保存命令参数

    std::string m_commandStr;

 

    // !当前使用的命令参数

    unsigned int m_nCurrentCommand;

 

    // !是否登陆标志。

    bool    m_bLogin;

};

 

 

#endif

#include "../Source/FTPManager.h"

 

static int SplitString( std::string strSrc, std::list<std::string> &strArray , std::string strFlag)

{

    int pos = 1; 

 

    while((pos = (int)strSrc.find_first_of(strFlag.c_str())) > 0) 

    {

        strArray.insert(strArray.end(), strSrc.substr(0 , pos));

        strSrc = strSrc.substr(pos + 1, strSrc.length() - pos - 1); 

    }

 

    strArray.insert(strArray.end(), strSrc.substr(0, strSrc.length()));

 

    return 0; 

}

 

CFTPManager::CFTPManager(void): m_bLogin(false)

{

    m_cmdSocket = socket(AF_INET, SOCK_STREAM, 0);

    

}

 

CFTPManager::~CFTPManager(void)

{

    std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, "");

 

    Send(m_cmdSocket, strCmdLine.c_str());

    close(m_cmdSocket);

    m_bLogin = false;

}

 

FTP_API CFTPManager::login2Server(const std::string &serverIP)

{

    std::string strPort;

    int pos = serverIP.find_first_of(":");

 

    if (pos > 0)

    {

        strPort = serverIP.substr(pos + 1, serverIP.length() - pos);

    }

    else

    {

        pos = serverIP.length();

        strPort = FTP_DEFAULT_PORT;

    }

 

    m_strServerIP = serverIP.substr(0, pos);

    m_nServerPort = atol(strPort.c_str());

 

    trace("IP: %s port: %d\n", m_strServerIP.c_str(), m_nServerPort);

 

    if (Connect(m_cmdSocket, m_strServerIP, m_nServerPort) < 0)

    {

        

        return -1;

    }

    

    m_strResponse = serverResponse(m_cmdSocket);

    printf("@@@@Response: %s", m_strResponse.c_str());

 

    return    parseResponse(m_strResponse);

}

 

FTP_API CFTPManager::inputUserName(const std::string &userName)

{

    std::string strCommandLine = parseCommand(FTP_COMMAND_USERNAME, userName);

 

    m_strUserName = userName;

 

    if (Send(m_cmdSocket, strCommandLine) < 0)

    {

        return -1;

    }

 

    m_strResponse = serverResponse(m_cmdSocket);

    printf("Response: %s\n", m_strResponse.c_str());

 

    return parseResponse(m_strResponse);

}

 

FTP_API CFTPManager::inputPassWord(const std::string &password)

{

    std::string strCmdLine = parseCommand(FTP_COMMAND_PASSWORD, password);

 

    m_strPassWord = password;

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

    else

    {

        m_bLogin = true;

 

        m_strResponse = serverResponse(m_cmdSocket);

        printf("Response: %s\n", m_strResponse.c_str());

 

        return parseResponse(m_strResponse);

    }

}

 

FTP_API CFTPManager::quitServer(void)

{

    std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, "");

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

    else

    {

        m_strResponse = serverResponse(m_cmdSocket);

        printf("Response: %s\n", m_strResponse.c_str());

 

        return parseResponse(m_strResponse);

    }

 

}

 

const std::string CFTPManager::PWD()

{

    std::string strCmdLine = parseCommand(FTP_COMMAND_CURRENT_PATH, "");

 

    if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)

    {

        return "";

    }

    else

    {

        return serverResponse(m_cmdSocket);

    }

}

 

 

FTP_API CFTPManager::setTransferMode(type mode)

{

    std::string strCmdLine;

 

    switch (mode)

    {

    case binary:

        strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "I");

        break;

    case ascii:

        strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "A");

        break;

    default:

        break;

    }

 

    if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)

    {

        assert(false);

    }

    else

    {    

        m_strResponse  = serverResponse(m_cmdSocket);

        printf("@@@@Response: %s", m_strResponse.c_str());

 

        return parseResponse(m_strResponse);

    }

}

 

 

const std::string CFTPManager::Pasv()

{

    std::string strCmdLine = parseCommand(FTP_COMMAND_PSAV_MODE, "");

 

    if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)

    {

        return "";

    }

    else

    {

        m_strResponse = serverResponse(m_cmdSocket);

 

        return m_strResponse;

    }

}

 

 

const std::string CFTPManager::Dir(const std::string &path)

{

    int dataSocket = socket(AF_INET, SOCK_STREAM, 0);

 

    if (createDataLink(dataSocket) < 0)

    {

        return "";

    }

    // 数据连接成功

    std::string strCmdLine = parseCommand(FTP_COMMAND_DIR, path);

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());

        close(dataSocket);

        return "";

    }

    else

    {

        trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());

        m_strResponse = serverResponse(dataSocket);

 

        trace("@@@@Response: \n%s\n", m_strResponse.c_str());

        close(dataSocket);

 

        return m_strResponse;

    }

    

}

 

 

FTP_API CFTPManager::CD(const std::string &path)

{

    assert(m_cmdSocket != INVALID_SOCKET);

 

    std::string strCmdLine = parseCommand(FTP_COMMAND_CHANGE_DIRECTORY, path);

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

        

    m_strResponse = serverResponse(m_cmdSocket);

    

    trace("@@@@Response: %s\n", m_strResponse.c_str());

    return parseResponse(m_strResponse);

}

 

FTP_API CFTPManager::DeleteFile(const std::string &strRemoteFile)

{

    assert(m_cmdSocket != INVALID_SOCKET);

 

    std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_FILE, strRemoteFile);

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

 

    m_strResponse = serverResponse(m_cmdSocket);

    printf("@@@@Response: %s\n", m_strResponse.c_str());

    return parseResponse(m_strResponse);

}

 

FTP_API CFTPManager::DeleteDirectory(const std::string &strRemoteDir)

{

    assert(m_cmdSocket != INVALID_SOCKET);

 

    std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_DIRECTORY, strRemoteDir);

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

    

    m_strResponse = serverResponse(m_cmdSocket);

 

    trace("@@@@Response: %s\n", m_strResponse.c_str());

    return parseResponse(m_strResponse);

}

 

FTP_API CFTPManager::CreateDirectory(const std::string &strRemoteDir)

{

    assert(m_cmdSocket != INVALID_SOCKET);

 

    std::string strCmdLine = parseCommand(FTP_COMMAND_CREATE_DIRECTORY, strRemoteDir);

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

    

    m_strResponse = serverResponse(m_cmdSocket);

 

    trace("@@@@Response: %s\n", m_strResponse.c_str());

    return parseResponse(m_strResponse);

}

 

FTP_API CFTPManager::Rename(const std::string &strRemoteFile, const std::string &strNewFile)

{

    assert(m_cmdSocket != INVALID_SOCKET);

 

    std::string strCmdLine = parseCommand(FTP_COMMAND_RENAME_BEGIN, strRemoteFile);

    Send(m_cmdSocket, strCmdLine);

    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());

 

    Send(m_cmdSocket, parseCommand(FTP_COMMAND_RENAME_END, strNewFile));

 

    m_strResponse = serverResponse(m_cmdSocket);

    trace("@@@@Response: %s\n", m_strResponse.c_str());

    return parseResponse(m_strResponse);

}

 

long CFTPManager::getFileLength(const std::string &strRemoteFile)

{

    assert(m_cmdSocket != INVALID_SOCKET);

 

    std::string strCmdLine = parseCommand(FTP_COMMAND_FILE_SIZE, strRemoteFile);

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

 

    m_strResponse = serverResponse(m_cmdSocket);

 

    trace("@@@@Response: %s\n", m_strResponse.c_str());

 

    std::string strData = m_strResponse.substr(0, 3);

    unsigned long val = atol(strData.c_str());

 

    if (val == 213)

    {

        strData = m_strResponse.substr(4);

        trace("strData: %s\n", strData.c_str());

        val = atol(strData.c_str());

 

        return val;

    }

 

    return -1;

}

 

 

void CFTPManager::Close(int sock)

{

    shutdown(sock, SHUT_RDWR);

    close(sock);

    sock = INVALID_SOCKET;

}

 

FTP_API CFTPManager::Get(const std::string &strRemoteFile, const std::string &strLocalFile)

{

    return downLoad(strRemoteFile, strLocalFile);

}

 

 

FTP_API CFTPManager::Put(const std::string &strRemoteFile, const std::string &strLocalFile)

{

    std::string strCmdLine;

    const unsigned long dataLen = FTP_DEFAULT_BUFFER;

    char strBuf[dataLen] = {0};

    unsigned long nSize = getFileLength(strRemoteFile);

    unsigned long nLen = 0;

//     struct stat sBuf;

// 

//     assert(stat(strLocalFile.c_str(), &sBuf) == 0);

//     trace("size: %d\n", sBuf.st_size);

 

    FILE *pFile = fopen(strLocalFile.c_str(), "rb");  // 以只读方式打开  且文件必须存在

    assert(pFile != NULL);

 

    int data_fd = socket(AF_INET, SOCK_STREAM, 0);

    assert(data_fd != -1);

 

    if (createDataLink(data_fd) < 0)

    {

        return -1;

    }

    

    if (nSize == -1)

    {

        strCmdLine = parseCommand(FTP_COMMAND_UPLOAD_FILE, strRemoteFile);

    }

    else

    {

        strCmdLine = parseCommand(FTP_COMMAND_APPEND_FILE, strRemoteFile);

    }

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        Close(data_fd);

        return -1;

    }

 

    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());

 

    fseek(pFile, nSize, SEEK_SET);

    while (!feof(pFile))

    {

        nLen = fread(strBuf, 1, dataLen, pFile);

        if (nLen < 0)

        {

            break;

        }

 

        if (Send(data_fd, strBuf) < 0)

        {

            Close(data_fd);

            return -1;

        }

    }

 

    trace("@@@@Response: %s\n", serverResponse(data_fd).c_str());

 

    Close(data_fd);

    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());

    fclose(pFile);

 

    return 0;

}

 

const std::string CFTPManager::parseCommand(const unsigned int command, const std::string &strParam)

{

    if (command < FTP_COMMAND_BASE || command > FTP_COMMAND_END)

    {

        return "";

    }

 

    std::string strCommandLine;

 

    m_nCurrentCommand = command;

    m_commandStr.clear();

 

    switch (command)

    {

    case FTP_COMMAND_USERNAME:

        strCommandLine = "USER ";

        break;

    case FTP_COMMAND_PASSWORD:

        strCommandLine = "PASS ";

        break;

    case FTP_COMMAND_QUIT:

        strCommandLine = "QUIT ";

        break;

    case FTP_COMMAND_CURRENT_PATH:

        strCommandLine = "PWD ";

        break;

    case FTP_COMMAND_TYPE_MODE:

        strCommandLine = "TYPE ";

        break;

    case FTP_COMMAND_PSAV_MODE:

        strCommandLine = "PASV ";

        break;

    case FTP_COMMAND_DIR:

        strCommandLine = "LIST ";

        break;

    case FTP_COMMAND_CHANGE_DIRECTORY:

        strCommandLine = "CWD ";

        break;

    case FTP_COMMAND_DELETE_FILE:

        strCommandLine = "DELE ";

        break;

    case FTP_COMMAND_DELETE_DIRECTORY:

        strCommandLine = "RMD ";

        break;

    case FTP_COMMAND_CREATE_DIRECTORY:

        strCommandLine = "MKD ";

        break;

    case FTP_COMMAND_RENAME_BEGIN:

        strCommandLine = "RNFR ";

        break;

    case FTP_COMMAND_RENAME_END:

        strCommandLine = "RNTO ";

        break;

    case FTP_COMMAND_FILE_SIZE:

        strCommandLine = "SIZE ";

        break;

    case FTP_COMMAND_DOWNLOAD_FILE:

        strCommandLine = "RETR ";

        break;

    case FTP_COMMAND_DOWNLOAD_POS:

        strCommandLine = "REST ";

        break;

    case FTP_COMMAND_UPLOAD_FILE:

        strCommandLine = "STOR ";

        break;

    case FTP_COMMAND_APPEND_FILE:

        strCommandLine = "APPE ";

        break;

    default :

        break;

    }

 

    strCommandLine += strParam;

    strCommandLine += "\r\n";

 

    m_commandStr = strCommandLine;

    trace("parseCommand: %s\n", m_commandStr.c_str());

 

    return m_commandStr;

}

 

FTP_API CFTPManager::Connect(int socketfd, const std::string &serverIP, unsigned int nPort)

{

    if (socketfd == INVALID_SOCKET)

    {

        return -1;

    }

 

    unsigned int argp = 1;

    int error = -1;

    int len = sizeof(int);

    struct sockaddr_in  addr;

    bool ret = false;

    timeval stime;

    fd_set  set;

 

    ioctl(socketfd, FIONBIO, &argp);  //设置为非阻塞模式

 

    memset(&addr, 0, sizeof(struct sockaddr_in));

    addr.sin_family = AF_INET;

    addr.sin_port    = htons(nPort);

    addr.sin_addr.s_addr = inet_addr(serverIP.c_str());

    bzero(&(addr.sin_zero), 8);

 

    trace("Address: %s %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

    

    if (connect(socketfd, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1)   //若直接返回 则说明正在进行TCP三次握手

    {

        stime.tv_sec = 20;  //设置为1秒超时

        stime.tv_usec = 0;

        FD_ZERO(&set);

        FD_SET(socketfd, &set);

 

        if (select(socketfd + 1, NULL, &set, NULL, &stime) > 0)   ///在这边等待 阻塞 返回可以读的描述符 或者超时返回0  或者出错返回-1

        {

            getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len);

            if (error == 0)

            {

                ret = true;

            }

            else

            {

                ret = false;

            }

        }

    }

    else

    {    trace("Connect Immediately!!!\n");

        ret = true;

    }

 

    argp = 0;

    ioctl(socketfd, FIONBIO, &argp);

 

    if (!ret)

    {

        close(socketfd);

        fprintf(stderr, "cannot connect server!!\n");

        return -1;

    }

 

    //fprintf(stdout, "Connect!!!\n");

 

    return 0;

}

 

 

const std::string CFTPManager::serverResponse(int sockfd)

{

    if (sockfd == INVALID_SOCKET)

    {

        return "";

    }

    

    int nRet = -1;

    char buf[MAX_PATH] = {0};

 

    m_strResponse.clear();

 

    while ((nRet = getData(sockfd, buf, MAX_PATH)) > 0)

    {

        buf[MAX_PATH - 1] = '\0';

        m_strResponse += buf;

    }

 

    return m_strResponse;

}

 

FTP_API CFTPManager::getData(int fd, char *strBuf, unsigned long length)

{

    assert(strBuf != NULL);

 

    if (fd == INVALID_SOCKET)

    {

        return -1;

    }

 

    memset(strBuf, 0, length);

    timeval stime;

    int nLen;

 

    stime.tv_sec = 1;

    stime.tv_usec = 0;

 

    fd_set    readfd;

    FD_ZERO( &readfd );

    FD_SET(fd, &readfd );

 

    if (select(fd + 1, &readfd, 0, 0, &stime) > 0)

    {

        if ((nLen = recv(fd, strBuf, length, 0)) > 0)

        {

            return nLen;

        }

        else

        {

            return -2;

        }

    }

    return 0;

}

 

FTP_API CFTPManager::Send(int fd, const std::string &cmd)

{

    if (fd == INVALID_SOCKET)

    {

        return -1;

    }

 

    return Send(fd, cmd.c_str(), cmd.length());

}

 

FTP_API CFTPManager::Send(int fd, const char *cmd, const size_t len)

{

    if((FTP_COMMAND_USERNAME != m_nCurrentCommand) 

        &&(FTP_COMMAND_PASSWORD != m_nCurrentCommand)

        &&(!m_bLogin))

    {

        return -1;

    }

 

    timeval timeout;

    timeout.tv_sec  = 1;

    timeout.tv_usec = 0;

 

    fd_set  writefd;

    FD_ZERO(&writefd);  

    FD_SET(fd, &writefd);

 

    if(select(fd + 1, 0, &writefd , 0 , &timeout) > 0)

    {

        size_t nlen  = len; 

        int nSendLen = 0; 

        while (nlen >0) 

        {

            nSendLen = send(fd, cmd , (int)nlen , 0);

 

            if(nSendLen == -1) 

                return -2; 

 

            nlen = nlen - nSendLen;

            cmd +=  nSendLen;

        }

        return 0;

    }

    return -1;

}

 

 

FTP_API CFTPManager::createDataLink(int data_fd)

{

    assert(data_fd != INVALID_SOCKET);

 

    std::string strData;

    unsigned long nPort = 0 ;

    std::string strServerIp ; 

    std::list<std::string> strArray ;

 

    std::string parseStr = Pasv();

 

    if (parseStr.size() <= 0)

    {

        return -1;

    }

 

    //trace("parseInfo: %s\n", parseStr.c_str());

 

    size_t nBegin = parseStr.find_first_of("(");

    size_t nEnd      = parseStr.find_first_of(")");

    strData          = parseStr.substr(nBegin + 1, nEnd - nBegin - 1);

 

    //trace("ParseAfter: %s\n", strData.c_str());

    if( SplitString( strData , strArray , "," ) <0)

        return -1;

 

    if( ParseString( strArray , nPort , strServerIp) < 0)

        return -1;

 

    //trace("nPort: %ld IP: %s\n", nPort, strServerIp.c_str());

 

    if (Connect(data_fd, strServerIp, nPort) < 0)

    {

        return -1;

    }

 

    return 0;

 

}

 

FTP_API CFTPManager::ParseString(std::list<std::string> strArray, unsigned long & nPort ,std::string & strServerIp)

{

    if (strArray.size() < 6 )

        return -1 ;

 

    std::list<std::string>::iterator citor;

    citor = strArray.begin();

    strServerIp = *citor;

    strServerIp += ".";

    citor ++;

    strServerIp += *citor;

    strServerIp += ".";

    citor ++ ;

    strServerIp += *citor;

    strServerIp += ".";

    citor ++ ;

    strServerIp += *citor;

    citor = strArray.end();

    citor--;

    nPort = atol( (*citor).c_str());

    citor--;

    nPort += atol( (*(citor)).c_str()) * 256 ;

    return 0 ; 

}

 

FILE *CFTPManager::createLocalFile(const std::string &strLocalFile)

{

    return fopen(strLocalFile.c_str(), "w+b");

}

 

FTP_API CFTPManager::downLoad(const std::string &strRemoteFile, const std::string &strLocalFile, const int pos, const unsigned int length)

{

    assert(length >= 0);

 

    FILE *file = NULL;

    unsigned long nDataLen = FTP_DEFAULT_BUFFER;

    char strPos[MAX_PATH]  = {0};

    int data_fd = socket(AF_INET, SOCK_STREAM, 0);

    

    assert(data_fd != -1);

 

    if ((length != 0) && (length < nDataLen))

    {

        nDataLen = length;

    }

    char *dataBuf = new char[nDataLen];

    assert(dataBuf != NULL);

 

    sprintf(strPos, "%d", pos);

 

    if (createDataLink(data_fd) < 0)

    {

        trace("@@@@ Create Data Link error!!!\n");

        return -1;

    }

 

    std::string strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_POS, strPos);

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());

 

    strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_FILE, strRemoteFile);

 

    if (Send(m_cmdSocket, strCmdLine) < 0)

    {

        return -1;

    }

    trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());

 

    file = createLocalFile(std::string(FTP_DEFAULT_PATH + strLocalFile));

    assert(file != NULL);

    

    int len = 0;

    int nReceiveLen = 0;

    while ((len = getData(data_fd, dataBuf, nDataLen)) > 0)

    {

        nReceiveLen += len;

 

        int num = fwrite(dataBuf, 1, len, file);

        memset(dataBuf, 0, sizeof(dataBuf));

    

        //trace("%s", dataBuf);

        trace("Num:%d\n", num);

        if (nReceiveLen == length && length != 0)

            break;

 

        if ((nReceiveLen + nDataLen) > length  && length != 0)

        {

            delete []dataBuf;

            nDataLen = length - nReceiveLen;

            dataBuf = new char[nDataLen];

        }

    }

 

    Close(data_fd);

    fclose(file);

    delete []dataBuf;

 

    return 0;

}

 

FTP_API CFTPManager::parseResponse(const std::string &str)

{

    assert(!str.empty());

 

    std::string strData = str.substr(0, 3);

    unsigned int val = atoi(strData.c_str());

 

    return val;

}

————————————————

版权声明:本文为「The_King_Cloud」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。