C++实现ftp客户端

C++实现ftp客户端
原创The_King_Cloud 发布于2012-10-19 17:09:42 阅读数 26454  收藏
展开
 
#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;
}


————————————————
版权声明:本文为CSDN博主「The_King_Cloud」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/The_King_Cloud/article/details/8090699

posted @ 2019-12-19 20:06  grj001  阅读(166)  评论(0编辑  收藏  举报