ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux/Unix 系统编程 — FTP客户端

2021-09-24 15:05:19  阅读:155  来源: 互联网

标签:FTP const ftp int char Unix fd Linux sockfd


尊重作者劳动成果,转载请注明出处,谢谢!

1. ftp.h

#ifndef ftp_H
#define ftp_H

#include "types.h"
#include "socket.h"

#ifdef __cplusplus
extern "C"
{
#endif
    int ftp_login(const char *servIp, unsigned short port, const char *user, const char *password);
    boolean ftp_quit(int sockfd);
    boolean ftp_getCurrentDirectory(int sockfd, char *directory);
    boolean ftp_changDirectory(int sockfd, const char *directory);
    boolean ftp_changDirectoryUp(int sockfd);
    boolean ftp_createDirectory(int sockfd, const char *directory);
    boolean ftp_fileList(int sockfd);
    boolean ftp_download(int sockfd, const char *remoteFileName, const char *filePath);
    boolean ftp_upload(int sockfd, const char *remoteFileName, const char *filePath);
#ifdef __cplusplus
}
#endif

#endif

2. ftp.c

#include "ftp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

static unsigned short strToHostAndPort(const char *str, char *host)
{
    int addr[6];
    sscanf(str, "%*[^(](%d,%d,%d,%d,%d,%d)", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]);

    bzero(host, strlen(host));
    sprintf(host, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);

    unsigned short port;
    port = addr[4] * 256 + addr[5];
    return port;
}

static boolean recvAndCheck(int sockfd, const char *code)
{
    char buf[1024] = {0};
    int nrecv = recv(sockfd, buf, 1024, 0);
    if (nrecv <= 0)
        return False;

    printf("%s\n", buf);
    return strncmp(buf, code, 3) == 0 ? True : False;
}

static boolean ftp_sendCommandWithResult(int sockfd, const char *cmd, const char *arg, const char *code, char *result)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    char *cmdBuf = (char *)malloc(strlen(cmd) + strlen(arg) + 10);
    sprintf(cmdBuf, "%s %s\r\n", cmd, arg);
    int cmdBufSize = strlen(cmdBuf);

    int nsend = send(sockfd, cmdBuf, cmdBufSize, 0);
    free(cmdBuf);
    if (nsend != cmdBufSize)
        return False;

    char buf[1024] = {0};
    int nrecv = recv(sockfd, buf, 1024, 0);
    printf("%s\n", buf);
    if (nrecv <= 0)
        return False;

    if (result != NULL)
        strcpy(result, buf);

    return strncmp(buf, code, 3) == 0 ? True : False;
}

static boolean ftp_sendCommand(int sockfd, const char *cmd, const char *arg, const char *code)
{
    return ftp_sendCommandWithResult(sockfd, cmd, arg, code, NULL);
}

//使用被动模式,并返回数据端口的文件描述符
static int ftp_uesPasvMode(int sockfd)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    char buf[1024] = {0};

    //227 Entering Passive Mode (192,168,1,100,191,160).
    if (!ftp_sendCommandWithResult(sockfd, "PASV", "", "227", buf))
        return False;

    char data_host[32] = {0};
    unsigned short data_port;
    data_port = strToHostAndPort(buf, data_host);

    return createTcpClient(data_host, data_port);
}

//ftp登录
int ftp_login(const char *servIp, unsigned short port, const char *user, const char *password)
{
    int sockfd = createTcpClient(servIp, port);
    if (sockfd == INVALID_SOCKET)
        return -1;

    //220 (vsFTPd 3.0.3)
    if (!recvAndCheck(sockfd, "220"))
    {
        close(sockfd);
        return INVALID_SOCKET;
    }

    //331 Please specify the password.
    if (!ftp_sendCommand(sockfd, "USER", user, "331"))
    {
        close(sockfd);
        return INVALID_SOCKET;
    }

    //230 Login successful.
    if (!ftp_sendCommand(sockfd, "PASS", password, "230"))
    {
        close(sockfd);
        return INVALID_SOCKET;
    }

    //200 Switching to Binary mode.
    if (!ftp_sendCommand(sockfd, "TYPE", "I", "200"))
    {
        close(sockfd);
        return INVALID_SOCKET;
    }

    return sockfd;
}

//ftp注销
boolean ftp_quit(int sockfd)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    //221 Goodbye.
    if (!ftp_sendCommand(sockfd, "QUIT", "", "221"))
        return False;

    close(sockfd);
    return True;
}

//ftp获取当前工作目录
boolean ftp_getCurrentDirectory(int sockfd, char *directory)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    //257 "/root" is the current directory
    char buf[1024];
    if (!ftp_sendCommandWithResult(sockfd, "PWD", "", "257", buf))
        return False;

    int i = 0;
    char *ptr = buf + 5;
    while (*ptr != '"')
    {
        directory[i++] = *ptr;
        ptr++;
    }

    directory[i] = '\0';
    return True;
}

//ftp更改当前工作目录
boolean ftp_changDirectory(int sockfd, const char *directory)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    //250 Directory successfully changed.
    return ftp_sendCommand(sockfd, "CWD", directory, "250");
}

//ftp更改当前工作目录为上一级目录
boolean ftp_changDirectoryUp(int sockfd)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    //250 Directory successfully changed.
    return ftp_sendCommand(sockfd, "CDUP", "", "250");
}

//ftp创建文件夹
boolean ftp_createDirectory(int sockfd, const char *directory)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    //257 "directory" created
    return ftp_sendCommand(sockfd, "MKD", directory, "257");
}

//ftp文件列表
boolean ftp_fileList(int sockfd)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    int data_fd = ftp_uesPasvMode(sockfd);
    if (data_fd == INVALID_SOCKET)
        return False;

    //150 Here comes the directory listing.
    if (!ftp_sendCommand(sockfd, "LIST", "", "150"))
    {
        close(data_fd);
        return False;
    }

    int bufSize = 1024;
    char buf[1024] = {0};
    int nrecv;
    while ((nrecv = recv(data_fd, buf, bufSize, 0)) > 0)
    {
        //drwx------    2 0        0               0 Sep 24 05:51 123
        //-rwx------    1 0        0           34980 Aug 20 04:28 devserv
        //-rw-------    1 0        0              30 Aug 20 03:58 devserv.conf
        printf("%s\n", buf);
    }

    close(data_fd);

    //226 Directory send OK.
    return recvAndCheck(sockfd, "226");
}

//ftp下载文件
boolean ftp_download(int sockfd, const char *remoteFileName, const char *filePath)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    int data_fd = ftp_uesPasvMode(sockfd);
    if (data_fd == INVALID_SOCKET)
        return False;

    //150 Opening BINARY mode data connection for "remoteFileName" (n bytes)
    if (!ftp_sendCommand(sockfd, "RETR", remoteFileName, "150"))
    {
        close(data_fd);
        return False;
    }

    int file_fd = open(filePath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    if (file_fd < 0)
    {
        close(data_fd);
        return False;
    }

    int bufSize = 4096;
    char buf[4096];
    int nread;
    while ((nread = recv(data_fd, buf, bufSize, 0)) > 0)
    {
        write(file_fd, buf, nread);
    }

    close(file_fd);
    close(data_fd);

    //226 Transfer complete.
    return recvAndCheck(sockfd, "226");
}

//ftp上传文件
boolean ftp_upload(int sockfd, const char *remoteFileName, const char *filePath)
{
    if (sockfd == INVALID_SOCKET)
        return False;

    if (access(filePath, F_OK) != 0)
        return False;

    int data_fd = ftp_uesPasvMode(sockfd);
    if (data_fd == INVALID_SOCKET)
        return False;

    //150 Ok to send data.
    if (!ftp_sendCommand(sockfd, "STOR", remoteFileName, "150"))
    {
        close(data_fd);
        return False;
    }

    int file_fd = open(filePath, O_RDONLY);
    if (file_fd < 0)
    {
        close(data_fd);
        return False;
    }

    int bufSize = 4096;
    char buf[4096];
    int nread;
    while ((nread = read(file_fd, buf, bufSize)) > 0)
    {
        send(data_fd, buf, nread, 0);
    }

    close(file_fd);
    close(data_fd);

    //226 Transfer complete
    return recvAndCheck(sockfd, "226");
}

 

标签:FTP,const,ftp,int,char,Unix,fd,Linux,sockfd
来源: https://www.cnblogs.com/chenyuxin/p/15330414.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有