Vxworks FTP移植到Sylixos使用笔记

类别内容
关键词Sylixos FTP Vxworks
摘 要Vxworks组件FTP移植和使用

1. 适用范围

本文适用对FTP有使用需求的工程师,讲述从FTP移植到使用。

2. 原理概述

文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,它工作在 OSI 模型的第七层, TCP 模型的第四层, 即应用层, 使用 TCP 传输而不是 UDP, 客户在和服务器建立连接前要经过一个“三次握手”的过程, 保证客户与服务器之间的连接是可靠的, 而且是面向连接, 为数据传输提供可靠保证。
FTP允许用户以文件操作的方式(如文件的增、删、改、查、传送等)与另一主机相互通信。然而, 用户并不真正登录到自己想要存取的计算机上面而成为完全用户, 可用FTP程序访问远程资源, 实现用户往返传输文件、目录管理以及访问电子邮件等等, 即使双方计算机可能配有不同的操作系统和文件存储方式。

2.1 FTP原理

FTP主要用来进行文件传输,包括命令信道和数据信道,命令信道用来交互命令控制,数据信道用来传输文件数据。
首先客户端需要进行登录FTP服务器,TCP建立连接,通过命令信道发送登录命令,传输数据时,通过命令信道交互数据端口号,彼此建立数据连接,数据可通过数据连接进行传输。
文件传输可选文件类型:ASCII码文件(默认的)/ 图像文件类型(二进制的)/ 本地文件类型(用于在具有不同字节大小主机间传送二进制数据)
与服务器连接分为两种模式:
主动 FTP :
    命令连接:客户端 >1024 端口 → 服务器 21 端口
    数据连接:客户端 >1024 端口 ← 服务器 20 端口
被动 FTP :
    命令连接:客户端 >1024 端口 → 服务器 21 端口
    数据连接:客户端 >1024 端口 ← 服务器 >1024 端口
  PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。 当需要传送数据时, 客户端在命令链路上用PORT命令告诉服务器:“我打开了***X端口,你过来连接我”。于是服务器从20端口向客户端的***X端口发送连接请求,建立 一条数据链路来传送数据。
  PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。 当需要传送数据时, 服务器在命令链路上用PASV命令告诉客户端:“我打开了***X端口,你过来连接我”。于是客户端向服务器的***X端口发送连接请求,建立一条数据链 路来传送数据。
早先所有客户端都使用主动模式,而且工作的很好,而现在因为客户端防火墙的存在,将会关闭一些端口,这样主动模式将会失败。在这种情况下就要使用被动模式,但是一些端口也可能被服务器的防火墙封掉。不过因为ftp服务器需要它的ftp服务连接到一定数量的客户端,所以他们总是支持被动模式的。这就是我们为什么要使用被动模式的原意,为了确保数据可以正确的传输,使用被动模式要明显优于主动模式。(译者注:主动(PORT)模式建立数据传输通道是由服务器端发起的,服务器使用20端口连接客户端的某一个大于1024的 端口;在被动(PASV)模式中,数据传输的通道的建立是由FTP客户端发起的,他使用一个大于1024的端口连接服务器的1024以上的某一个端口)
主动模式传送数据时是“服务器”连接到“客户端”的端口;
被动模式传送数据是“客户端”连接到“服务器”的端口。
主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。
被动模式只需要服务器端开放端口给客户端连接就行了。
FTP服务器一般都支持主动和被动模式,连接采用何种模式是有FTP客户端软件决定。
FTP被动模式的出现原因
在FTP的历史中,本来只有主动模式的,但是为什么又出现了被动模式呢?这又牵涉到另外一个问题了。
在很久以前(我也不知道多久),地球上还没有什么共享上网这种技术,但是后来出现了,所以也就有了下面的问题,大家都知道,共享上网就是很 多台电脑共享一个公网IP去使用internet,再打个比喻吧,某个局域网共享210.33.25.1这个公网IP上网,当一个内网用户 192.168.0.100去访问外网的FTP服务器时,如果采用主动模式的话,192.168.0.1告诉了FTP服务器我需要某个文件和我打开了x端 口之后,由于共享上网的原因,192.168.0.1在出网关的时候自己的IP地址已经被翻译成了210.33.25.1这个公网IP,所以服务器端收到 的消息也就是210.33.25.1需要某个文件并打开了x端口,FTP服务器就会往210.33.25.1的x端口传数据,这样当然会连接不成功了,因为打开x端口的并不是210.33.25.1这个地址,在这种情况下被动模式就有用了,相信大家已经能够理解被动模式是怎么个连接法了吧。
  在主动模式中,FTP的两个端口是相对固定的,如果命令端口是x的话,那数据端口就是x-1,也就是说默认情况下,命令端口是21,数据端口就是20;你把命令端口改成了123,那么数据端口就是122。这样使用防火墙就很方便了,只要开通这两个端口就可以了,但是如果客户端是共享上网的话那岂不是不能正常使用FTP了,这样还是不行,一定需要被动模式。
  在被动模式中就麻烦了些,默认情况下命令端口是21,但是数据端口是随机的
因此推荐使用被动模式。

3. 准备工作

3.1 环境准备

  • FTP服务器关闭防火墙
  • FTP服务器开启FTP

3.2 资源准备

  • Vxworks源码(包括组件ftpLib.c)
  • Sylixos的工程文件

4. 技术实现

4.1 base工程和app工程设置

base工程选中libVxWorks,app工程进行连接so动态库。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.2 ftpLib移植

FTP实现依赖TCP进行通信,均使用POSIX标准接口,几乎不需要修改,主要针对警告以及缺失函数部分。

#ifndef SYLIXOS
#include <remLib.h>
#endif
#include <hostLib.h>
#ifndef SYLIXOS
#include <ftpLib.h>
#include <applUtilLib.h>
#else
#include "ftpLib.h"
#include "taskLibCommon.h"
#include <SylixOS.h>

#define log_err(__LOG_LEVEL, ...)      \
    do{\
    if((__LOG_LEVEL) & 1)\
    {\
        if((__LOG_LEVEL) & LOG_ERRNO)\
        {\
            printf("error #");\
        }\
    printf(__VA_ARGS__);printf("\r\n");\
    }\
}while(0);
#define log_info      log_err
#define log_warning   log_err

#endif

STATUS logLevelChange
    (
    int category,    /* logger category */
    UINT mask        /* bit mask of levels to log at - 0x00..0xff */
    )
    {

    return OK;
    }

#ifndef SYLIXOS
            log_err (FTP_LOG, "Timeout %lu sec.", replyTimeOut.tv_sec);
#else
            log_err (FTP_LOG, "Timeout %lu sec.", (ULONG)replyTimeOut.tv_sec);
#endif

#ifndef SYLIXOS
    int len;
#else
    UINT len;
#endif

#ifndef SYLIXOS
        bzero ((char *) &dataAddr, sizeof (SOCKADDR));
#else
        bzero ((char *) &dataAddr, sizeof (SOCKADDR_IN));
#endif

#ifndef SYLIXOS
    int len;
#else
    UINT len;
#endif

#ifndef SYLIXOS
    int fromlen = sizeof (from);
#else
    UINT fromlen = sizeof (from);
#endif

#ifndef SYLIXOS
             log_err (FTP_LOG, "select timeout after %lu sec.", replyTime.tv_sec);
#else
             log_err (FTP_LOG, "select timeout after %lu sec.", (ULONG)replyTime.tv_sec);
#endif

c文件需要将警告部分优化,以及确实函数的实现,h文件主要缺失一些宏定义,进行补全移植全部完成。

#ifndef SYLIXOS
#include <vxWorks.h>
#include <vwModNum.h>
#endif

#ifdef SYLIXOS
#include <vxWorksCommon.h>

#define MAX_IDENTITY_LEN              100
#define MIN_RESV_PORT                 600
#define MAX_RESV_PORT                 1023

#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN                64
#endif

#define FTP_LOG                       1

#define LOG_ERRNO                     0x10 /* log errno */

#undef  FTP_TRANSIENT_MAX_RETRY_COUNT
#define FTP_TRANSIENT_MAX_RETRY_COUNT 100
#undef  FTP_TRANSIENT_RETRY_INTERVAL
#define FTP_TRANSIENT_RETRY_INTERVAL  0
#undef  FTP_DEBUG_OPTIONS
#define FTP_DEBUG_OPTIONS             0
#undef  FTP_TIMEOUT
#define FTP_TIMEOUT                   0

extern UINT32  ftplTransientMaxRetryCount;   /* Retry just once for now */
extern UINT32  ftplTransientRetryInterval;   /* Default with no delay */
#endif

5. 如何使用FTP

一般应用都需要进行初始化才能使用,初始化是可以省略的,只是针对一些时间的设置等。

/*******************************************************************************
*
* ftpTransientFatal - example applette to terminate FTP transient host responses
*
* ftpXfer will normally retry a command if the host responds with a 4xx
*     reply.   If this applette is installed,  it can immediately terminate
*     the retry sequence.
*
*
* RETURNS : TRUE - Terminate retry attempts
*           FALSE - Continue retry attempts
*
*
* SEE ALSO : ftpTransientFatalInstall(), ftpTransientConfigSet()
*
*/

LOCAL BOOL ftpTransientFatal
    (
    UINT32 reply /* Three digit code defined in RFC #640 */
    )
    {
    switch (reply)
        {
        case (421): /* Service not available */
        case (450): /* File unavailable */
        case (451): /* error in processing */
        case (452): /* insufficient storage */
            {
            /* yes, these are actually non-recoverable replies */
            return (TRUE);
            }
            /* attempt to retry the last command */
        default:
        return (FALSE);
        }
    }

#define FTP_TRANSIENT_FATAL ftpTransientFatal
/******************************************************************************
*
* usrFtpInit - initialize FTP parameters
*
* This routine configures ftp client parameters.
* defined by the user via the project facility.
*
* RETURNS: OK or ERROR
*
* NOMANUAL
*/

STATUS usrFtpInit (void)
    {
    ftpLibInit (FTP_TIMEOUT);
    ftplTransientMaxRetryCount = FTP_TRANSIENT_MAX_RETRY_COUNT; /* 重试次数 */
    ftplTransientRetryInterval = FTP_TRANSIENT_RETRY_INTERVAL; /* 重试间隔 */
    ftpTransientFatalInstall ( FTP_TRANSIENT_FATAL ); /* 可以省略 */
    ftpLibDebugOptionsSet ( FTP_DEBUG_OPTIONS );    /* 设置打印等级 */

    return OK;
    }

FTP使用主要使用ftpXfer函数进行文件的上传和下载。ftpXfer函数内部的函数也可单独使用,如果有需求可参照ftpXfer函数自己定制。

STATUS ftpXfer
    (
    char *host,         /* name of server host */
    char *user,         /* user name for host login */
    char *passwd,       /* password for host login */
    char *acct,         /* account for host login */
    char *cmd,          /* command to send to host */
    char *dirname,      /* directory to 'cd' to before sending command */
    char *filename,     /* filename to send with command */
    int *pCtrlSock,     /* where to return control socket fd */
    int *pDataSock      /* where to return data socket fd, */
                        /* (NULL == don't open data connection) */
    )

文件上传和下载例子。

#include <stdio.h>
#include "ftpLib.h"
#include "socket.h"

#define HOST          "192.168.1.10"
#define USER          "anonymous"                                      /* 匿名方式账户名                     */
#define PWD           " "                                              /* 密码任意                           */
#define W_DIR         "/ftptest"                                       /* 文件夹路径                         */

/*
 * 这条命令让服务器给客户传送一份在路径名中指定的文件
 * 的副本。这不会影响该文件在服务器站点上的状态和内容。
 */
#define RD_CMD        "RETR %s"
#define WR_CMD        "STOR %s"                                        /* 让服务器接收一个来自数据连接的文件 */
#define FILE          "fromserver.txt"
#define TOSERVER_FILE "toserver.txt"

/*
 *  ftp 下载一个文件
 */
void FtpDownload()
{
 int ctrlSock;
 int dataSock;
 char buf[512];
 int nBytes;

 if(ERROR == ftpXfer(HOST, USER, PWD, "", RD_CMD, W_DIR, FILE, &ctrlSock, &dataSock))
 {
  printf("\r\n ftp connected failed!");
  return ;
 }

 while((nBytes = read(dataSock, buf, sizeof(buf))) > 0)
 {
  printf("\r\n it is [%s]", buf);
 }

 close(dataSock);

 if(ERROR == nBytes)
  printf("\r\nit is reading error.");

 if(ftpCommand(ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0) == FTP_COMPLETE)
  printf("\r\nftp is completed");
 close(ctrlSock);
}

/*
 *  ftp 上传一个文件
 */
void FtpUpload ()
{
    int ctrlSock;
    int dataSock;
    int nBytes;

#define FTP_WRITE_TIMEOUT_DEFAULT 30

    struct timeval tm;
    tm.tv_sec = FTP_WRITE_TIMEOUT_DEFAULT;
    tm.tv_usec = 0;

    if(ERROR == ftpXfer(HOST, USER, PWD, "", WR_CMD, W_DIR, TOSERVER_FILE, &ctrlSock, &dataSock))
    {
     printf("\r\n ftp connected failed!");
     return ;
    }

    setsockopt(dataSock,SOL_SOCKET,SO_SNDTIMEO,(char*)&tm,sizeof(struct timeval));

    const PCHAR const ptr = "This is a test!.";

    nBytes = write (dataSock, ptr, strlen(ptr));

    close(dataSock);

    if(ERROR == nBytes)
        printf("\r\nit is reading error.");

    if(ftpCommand(ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0) == FTP_COMPLETE)
        printf("\r\nftp is completed");
    close(ctrlSock);
}

可以看到使用了两个信道,命令信道和数据信道。
命令
控制信道进行命令的传输,简要列举了一些控制命令。
在这里插入图片描述

6. 总结

大概了解FTP原理即可,ftpLib已经实现了FTP功能,知道两个信道,使用时就得心应手了。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值