用C语言实现FTP协议客户端的主要功能

用C语言实现FTP协议客户端的主要功能

来自:http://www.tanhao.me/code/1312.html

最近在研究FTP客户端的实现,最初我直接使用的Cocoa中提供的CFFTPStream相关的函数,但最终发现用此方法实现的FTP客户端有很大的局限性,于是我便找到了一份在Windows上用C语言实现的FTP客户端代码,但在Mac OSX系统下却编译不过,于是我便根据这份代码改写了一个份在类Unix上可以正常使用的FTP函数,下面帖上所有的代码:

7月19日更新,修复了其实多处BUG,完善了FTP的List,上传,下载的接口。


头文件(THFTPAPI.h):

//
//  THFTPAPI.h
//  MyFTP
//
//  Created by TanHao on 13-6-6.
//  Copyright (c) 2013年 http://www.tanhao.me. All rights reserved.
//

//链接服务器
int ftp_connect( char *host, int port, char *user, char *pwd );
//断开服务器
int ftp_quit( int c_sock);

//设置表示类型
int ftp_type( int c_sock, char mode );

//改变工作目录
int ftp_cwd( int c_sock, char *path );
//回到上一层目录
int ftp_cdup( int c_sock );
//创建目录
int ftp_mkd( int c_sock, char *path );
//列表
int ftp_list( int c_sock, char *path, void **data, unsigned long long *data_len);

//下载文件
int ftp_retrfile( int c_sock, char *s, char *d ,unsigned long long *stor_size, int *stop);
//上传文件
int ftp_storfile( int c_sock, char *s, char *d ,unsigned long long *stor_size, int *stop);

//修改文件名&移动目录
int ftp_renamefile( int c_sock, char *s, char *d );
//删除文件
int ftp_deletefile( int c_sock, char *s );
//删除目录
int ftp_deletefolder( int c_sock, char *s );

实现(THFTPAPI.c):

//
//  THFTPAPI.c
//  MyFTP
//
//  Created by TanHao on 13-6-6.
//  Copyright (c) 2013年 http://www.tanhao.me. All rights reserved.
//

#include "THFTPAPI.h"

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>

//创建一个socket并返回
int socket_connect(char *host,int port)
{
    struct sockaddr_in address;
    int s, opvalue;
    socklen_t slen;
    
    opvalue = 8;
    slen = sizeof(opvalue);
    memset(&address, 0, sizeof(address));
    
    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
        setsockopt(s, IPPROTO_IP, IP_TOS, &opvalue, slen) < 0)
        return -1;
    
    //设置接收和发送超时
    struct timeval timeo = {15, 0};
    setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
    
    address.sin_family = AF_INET;
    address.sin_port = htons((unsigned short)port);
    
    struct hostent* server = gethostbyname(host);
    if (!server)
        return -1;
    
    memcpy(&address.sin_addr.s_addr, server->h_addr, server->h_length);
    
    if (connect(s, (struct sockaddr*) &address, sizeof(address)) == -1)
        return -1;
    
    return s;
}

//连接到一个ftp的服务器,返回socket
int connect_server( char *host, int port )
{    
    int       ctrl_sock;
    char      buf[512];
    int       result;
    ssize_t   len;
    
    ctrl_sock = socket_connect(host, port);
    if (ctrl_sock == -1) {
        return -1;
    }
    
    len = recv( ctrl_sock, buf, 512, 0 );
    buf[len] = 0;
    sscanf( buf, "%d", &result );
    if ( result != 220 ) {
        close( ctrl_sock );
        return -1;
    }
    
    return ctrl_sock;
}

//发送命令,返回结果
int ftp_sendcmd_re( int sock, char *cmd, void *re_buf, ssize_t *len)
{
    char        buf[512];
    ssize_t     r_len;
    
    if ( send( sock, cmd, strlen(cmd), 0 ) == -1 )
        return -1;
    
    r_len = recv( sock, buf, 512, 0 );
    if ( r_len < 1 ) return -1;
    buf[r_len] = 0;
    
    if (len != NULL) *len = r_len;
    if (re_buf != NULL) sprintf(re_buf, "%s", buf);
    
    return 0;
}

//发送命令,返回编号
int ftp_sendcmd( int sock, char *cmd )
{
    char     buf[512];
    int      result;
    ssize_t  len;
    
    result = ftp_sendcmd_re(sock, cmd, buf, &len);
    if (result == 0)
    {
        sscanf( buf, "%d", &result );
    }
    
    return result;
}

//登录ftp服务器
int login_server( int sock, char *user, char *pwd )
{
    char    buf[128];
    int     result;
    
    sprintf( buf, "USER %s\r\n", user );
    result = ftp_sendcmd( sock, buf );
    if ( result == 230 ) return 0;
    else if ( result == 331 ) {
        sprintf( buf, "PASS %s\r\n", pwd );
        if ( ftp_sendcmd( sock, buf ) != 230 ) return -1;
        return 0;
    }
    else
        return -1;
}

int create_datasock( int ctrl_sock )
{
    int     lsn_sock;
    int     port;
    int     len;
    struct sockaddr_in sin;
    char    cmd[128];
    
    lsn_sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
    if ( lsn_sock == -1 ) return -1;
    memset( (char *)&sin, 0, sizeof(sin) );
    sin.sin_family = AF_INET;
    if( bind(lsn_sock, (struct sockaddr *)&sin, sizeof(sin)) == -1 ) {
        close( lsn_sock );
        return -1;
    }
    
    if( listen(lsn_sock, 2) == -1 ) {
        close( lsn_sock );
        return -1;
    }
    
    len = sizeof( struct sockaddr );
    if ( getsockname( lsn_sock, (struct sockaddr *)&sin, (socklen_t *)&len ) == -1 )
    {
        close( lsn_sock );
        return -1;
    }
    port = sin.sin_port;
    
    if( getsockname( ctrl_sock, (struct sockaddr *)&sin, (socklen_t *)&len ) == -1 )
    {
        close( lsn_sock );
        return -1;
    }
    
    sprintf( cmd, "PORT %d,%d,%d,%d,%d,%d\r\n",
            sin.sin_addr.s_addr&0x000000FF,
            (sin.sin_addr.s_addr&0x0000FF00)>>8,
            (sin.sin_addr.s_addr&0x00FF0000)>>16,
            (sin.sin_addr.s_addr&0xFF000000)>>24,
            port>>8, port&0xff );
    
    if ( ftp_sendcmd( ctrl_sock, cmd ) != 200 ) {
        close( lsn_sock );
        return -1;
    }
    return lsn_sock;
}

//连接到PASV接口
int ftp_pasv_connect( int c_sock )
{
    int     r_sock;
    int     send_re;
    ssize_t len;
    int     addr[6];
    char    buf[512];
    char    re_buf[512];
    
    //设置PASV被动模式
    bzero(buf, sizeof(buf));
    sprintf( buf, "PASV\r\n");
    send_re = ftp_sendcmd_re( c_sock, buf, re_buf, &len);
    if (send_re == 0) {
        sscanf(re_buf, "%*[^(](%d,%d,%d,%d,%d,%d)",&addr[0],&addr[1],&addr[2],&addr[3],&addr[4],&addr[5]);
    }
    
    //连接PASV端口
    bzero(buf, sizeof(buf));
    sprintf( buf, "%d.%d.%d.%d",addr[0],addr[1],addr[2],addr[3]);
    r_sock = socket_connect(buf,addr[4]*256+addr[5]);
    
    return r_sock;
}

//表示类型
int ftp_type( int c_sock, char mode )
{
    char    buf[128];
    sprintf( buf, "TYPE %c\r\n", mode );
    if ( ftp_sendcmd( c_sock, buf ) != 200 )
        return -1;
    else
        return 0;
}

//改变工作目录
int ftp_cwd( int c_sock, char *path )
{
    char    buf[128];
    int     re;
    sprintf( buf, "CWD %s\r\n", path );
    re = ftp_sendcmd( c_sock, buf );
    if ( re != 250 )
        return -1;
    else
        return 0;
}

//回到上一层目录
int ftp_cdup( int c_sock )
{
    int     re;
    re = ftp_sendcmd( c_sock, "CDUP\r\n" );
    if ( re != 250 )
        return re;
    else
        return 0;
}

//创建目录
int ftp_mkd( int c_sock, char *path )
{
    char    buf[512];
    int     re;
    sprintf( buf, "MKD %s\r\n", path );
    re = ftp_sendcmd( c_sock, buf );
    if ( re != 257 )
        return re;
    else
        return 0;
}

//列表
int ftp_list( int c_sock, char *path, void **data, unsigned long long *data_len)
{
    int     d_sock;
    char    buf[512];
    int     send_re;
    int     result;
    ssize_t     len,buf_len,total_len;
    
    //连接到PASV接口
    d_sock = ftp_pasv_connect(c_sock);
    if (d_sock == -1) {
        return -1;
    }
    
    //发送LIST命令
    bzero(buf, sizeof(buf));
    sprintf( buf, "LIST %s\r\n", path);
    send_re = ftp_sendcmd( c_sock, buf );
    if (send_re >= 300 || send_re == 0)
        return send_re;
    
    len=total_len = 0;
    buf_len = 512;
    void *re_buf = malloc(buf_len);
    while ( (len = recv( d_sock, buf, 512, 0 )) > 0 )
    {
        if (total_len+len > buf_len)
        {
            buf_len *= 2;
            void *re_buf_n = malloc(buf_len);
            memcpy(re_buf_n, re_buf, total_len);
            free(re_buf);
            re_buf = re_buf_n;
        }
        memcpy(re_buf+total_len, buf, len);
        total_len += len;
    }
    close( d_sock );
    
    //向服务器接收返回值
    bzero(buf, sizeof(buf));
    len = recv( c_sock, buf, 512, 0 );
    buf[len] = 0;
    sscanf( buf, "%d", &result );
    if ( result != 226 )
    {
        free(re_buf);
        return result;
    }
    
    *data = re_buf;
    *data_len = total_len;
    
    return 0;
}

/*
//获得文件
int ftp_retrfile( int c_sock, char *s, char *d )
{
    int     d_sock;
    int     l_sock;
    struct sockaddr sin;
    ssize_t     len;
    char    buf[512];
    int     handle;
    
    handle = open( d,  O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE );
    if ( handle == -1 ) return -1;
    l_sock = create_datasock( c_sock );
    if ( l_sock == -1 ) return -1;
    sprintf( buf, "RETR %s\r\n", s );
    if ( ftp_sendcmd( c_sock, buf ) >= 300 ) return -1;
    d_sock = accept( l_sock, &sin, (socklen_t *)&len );
    close( l_sock );
    while ( (len = recv( d_sock, buf, 512, 0 )) > 0 ) {
        write( handle, buf, len );
    }
    len = recv( c_sock, buf, 512, 0 );
    buf[len] = 0;
    close( d_sock );
    close( handle );
    return 0;
}
 */

int ftp_retrfile( int c_sock, char *s, char *d ,unsigned long long *stor_size, int *stop)
{
    int     d_sock;
    ssize_t     len,write_len;
    char    buf[512];
    int     handle;
    int     result;
    
    //打开本地文件
    handle = open( d,  O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE );
    if ( handle == -1 ) return -1;
    
    //设置传输模式
    ftp_type(c_sock, 'I');
    
    //连接到PASV接口
    d_sock = ftp_pasv_connect(c_sock);
    if (d_sock == -1)
    {
        close(handle);
        return -1;
    }
    
    //发送STOR命令
    bzero(buf, sizeof(buf));
    sprintf( buf, "RETR %s\r\n", s );
    result = ftp_sendcmd( c_sock, buf );
    if (result >= 300 || result == 0)
    {
        close(handle);
        return result;
    }
    
    //开始向PASV读取数据
    bzero(buf, sizeof(buf));
    while ( (len = recv( d_sock, buf, 512, 0 )) > 0 ) {
        write_len = write( handle, buf, len );
        if (write_len != len || (stop != NULL && *stop))
        {
            close( d_sock );
            close( handle );
            return -1;
        }
        
        if (stor_size != NULL)
        {
            *stor_size += write_len;
        }
    }
    close( d_sock );
    close( handle );
    
    //向服务器接收返回值
    bzero(buf, sizeof(buf));
    len = recv( c_sock, buf, 512, 0 );
    buf[len] = 0;
    sscanf( buf, "%d", &result );
    if ( result >= 300 ) {
        return result;
    }
    return 0;
}

//保存文件
int ftp_storfile( int c_sock, char *s, char *d ,unsigned long long *stor_size, int *stop)
{
    int     d_sock;
    ssize_t     len,send_len;
    char    buf[512];
    int     handle;
    int send_re;
    int result;
    
    //打开本地文件
    handle = open( s,  O_RDONLY);
    if ( handle == -1 ) return -1;
    
    //设置传输模式
    ftp_type(c_sock, 'I');
    
    //连接到PASV接口
    d_sock = ftp_pasv_connect(c_sock);
    if (d_sock == -1)
    {
        close(handle);
        return -1;
    }
    
    //发送STOR命令
    bzero(buf, sizeof(buf));
    sprintf( buf, "STOR %s\r\n", d );
    send_re = ftp_sendcmd( c_sock, buf );
    if (send_re >= 300 || send_re == 0)
    {
        close(handle);
        return send_re;
    }
    
    //开始向PASV通道写数据
    bzero(buf, sizeof(buf));
    while ( (len = read( handle, buf, 512)) > 0)
    {
        send_len = send(d_sock, buf, len, 0);
        if (send_len != len ||
            (stop != NULL && *stop))
        {
            close( d_sock );
            close( handle );
            return -1;
        }
        
        if (stor_size != NULL)
        {
            *stor_size += send_len;
        }
    }
    close( d_sock );
    close( handle );
    
    //向服务器接收返回值
    bzero(buf, sizeof(buf));
    len = recv( c_sock, buf, 512, 0 );
    buf[len] = 0;
    sscanf( buf, "%d", &result );
    if ( result >= 300 ) {
        return result;
    }
    return 0;
}

//修改文件名&移动目录
int ftp_renamefile( int c_sock, char *s, char *d )
{
    char    buf[512];
    int     re;
    
    sprintf( buf, "RNFR %s\r\n", s );
    re = ftp_sendcmd( c_sock, buf );
    if ( re != 350 ) return re;
    sprintf( buf, "RNTO %s\r\n", d );
    re = ftp_sendcmd( c_sock, buf );
    if ( re != 250 ) return re;
    return 0;
}

//删除文件
int ftp_deletefile( int c_sock, char *s )
{
    char    buf[512];
    int     re;
    
    sprintf( buf, "DELE %s\r\n", s );
    re = ftp_sendcmd( c_sock, buf );
    if ( re != 250 ) return re;
    return 0;
}

//删除目录
int ftp_deletefolder( int c_sock, char *s )
{
    char    buf[512];
    int     re;
    
    sprintf( buf, "RMD %s\r\n", s );
    re = ftp_sendcmd( c_sock, buf );
    if ( re != 250 ) return re;
    return 0;
}

//链接服务器
int ftp_connect( char *host, int port, char *user, char *pwd )
{
    int     c_sock;
    c_sock = connect_server( host, port );
    if ( c_sock == -1 ) return -1;
    if ( login_server( c_sock, user, pwd ) == -1 ) {
        close( c_sock );
        return -1;
    }
    return c_sock;
}

//断开服务器
int ftp_quit( int c_sock)
{
    int re = 0;
    re = ftp_sendcmd( c_sock, "QUIT\r\n" );
    close( c_sock );
    return re;
}



  • 3
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C语言可以用来创建FTP(文件传输协议客户端和服务器。FTP是一种用于在计算机之间进行文件传输的标准协议,它允许用户通过网络上传和下载文件。 对于FTP客户端,可以使用C语言socket编程来创建一个连接到FTP服务器的套接字。使用套接字来与服务器建立连接后,可以使用C语言的网络编程函数来实现FTP命令的发送和接收。例如,可以使用C语言的send和recv函数来发送和接收FTP命令和数据。 对于FTP服务器,可以使用C语言socket编程来创建一个监听特定连接请求的套接字。当客户端连接到服务器时,服务器可以使用C语言的网络编程函数来处理客户端FTP命令和数据。服务器可以使用C语言的文件操作函数来读写文件,并使用FTP命令在客户端和服务器之间进行传输。 为了建立一个完整的FTP客户端和服务器,还需要实现一些FTP命令,如登录、文件上传、文件下载等。这些命令可以使用C语言编写的函数来处理。FTP客户端和服务器之间的通信可以通过套接字进行,可以使用C语言的字符串处理函数来解析和处理FTP命令和数据。 总之,通过使用C语言socket编程功能和网络编程函数,可以创建一个FTP客户端和服务器。使用C语言提供的文件操作函数和字符串处理函数,可以实现FTP命令的处理和文件传输。 ### 回答2: 创建C语言FTP客户端和服务器主要涉及以下几个步骤: 1. FTP服务器端的创建: - 创建一个TCP服务器套接字。 - 绑定套接字到特定的IP地址和端口号。 - 监听连接请求,等待客户端进行连接。 - 接受客户端连接请求。 - 接收客户端发送的FTP命令,解析命令,并执行相应的操作,如上传、下载、删除等。 - 处理客户端的连接断开请求。 2. FTP客户端的创建: - 创建一个TCP客户端套接字。 - 连接到FTP服务器的IP地址和端口号。 - 发送FTP命令给服务器端,如登录、上传、下载等。 - 接收服务器端发送的响应信息,并进行相应的处理。 - 处理与服务器的连接断开请求。 3. FTP协议实现: - 根据FTP协议规定,实现FTP命令的解析与执行。 - 使用TCP协议进行数据的传输,如下载文件时,通过TCP连接发送文件的内容。 - 对于大文件的传输,可以分割成多个小块进行传输,并进行相应的校验,确保数据的完整性。 - 处理用户名和密码的验证,以及权限的控制。 4. 安全性的考虑: - 使用SSL/TLS协议对网络传输进行加密,确保数据的安全性。 - 对于文件传输过程中的敏感信息,如用户名和密码,使用加密算法进行保护。 通过以上步骤,可以实现基本的C语言FTP客户端和服务器。这些代码通常需要结合使用C语言的网络编程库,如Socket编程库,来实现网络连接和数据传输的功能。此外,还可以根据需求对代码进行优化和扩展,如支持断点续传、多线程下载等功能。 ### 回答3: C语言可以用于创建FTP(文件传输协议客户端和服务器。FTP是一种用于在网络上传输文件的标准协议。下面将分别介绍如何使用C语言创建FTP客户端和服务器。 要创建FTP客户端,我们可以使用C语言的套接字编程。套接字是一种用于实现网络通信的接口。首先,我们需要创建一个套接字来建立与服务器的连接。然后,我们可以使用C语言的相关函数来实现FTP的各种命令,如登录、上传文件、下载文件等。最后,通过发送和接收套接字上的数据来实现与服务器的通信。 要创建FTP服务器,我们同样可以使用C语言的套接字编程。首先,我们需要创建一个套接字并绑定到一个特定的端口上,以便客户端可以连接到服务器。然后,我们可以使用C语言的相关函数来实现FTP的各种命令的处理,如处理登录请求、处理文件上传请求、处理文件下载请求等。最后,通过发送和接收套接字上的数据来实现客户端的通信。 在创建FTP客户端和服务器时,我们需要注意网络编程的一些基本概念和技术,如IP地址和端口号的使用、套接字的创建和使用、数据的发送和接收等。此外,还需要了解FTP协议的基本工作原理和相关命令的用法。 总的来说,使用C语言可以很好地实现FTP客户端和服务器的创建。但是,这需要一定的网络编程和C语言编程的知识和经验。对于初学者来说,可能需要更多的学习和实践才能熟练掌握。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值