第 2 章 - 安装和使用 Azure RTOS NetX FTP

本章介绍与安装、设置和使用 Azure RTOS NetX FTP 组件相关的各种问题。

产品分发

可以从我们的公共源代码存储库获取 Azure RTOS NetX,网址为:https://github.com/azure-rtos/netx/。 此软件包包含两个源文件和一个 PDF 文件,该 PDF 文件包含本文档,如下所示:

  • nx_ftp.h:NetX FTP 的头文件
  • nx_ftp_client.c:NetX FTP 客户端的 C 源文件
  • nx_ftp_server.c:NetX FTP 服务器的 C 源文件
  • filex_stub.h:存根文件,如果 FileX 不存在
  • nx_ftp.pdf:NetX FTP 的 PDF 说明
  • demo_netx_ftp.c:FTP 演示系统

FTP 安装

若要使用 NetX FTP,应将之前提到的全部分发文件复制到安装了 NetX 的同一目录中。 例如,如果 NetX 安装在“\threadx\arm7\green”目录中,则应将 nx_ftp.h、nx_ftp_client.c 和 nx_ftp_server.c 文件复制到该目录中。

使用 FTP

NetX FTP 易于使用。 基本上来说,应用程序代码必须包含 nx_ftp.h 和 tx_api.h、fx_api.h 或 nx_api.h,才能使用 ThreadX、FileX 或 NetX。 在包含 nx_ftp.h 之后,应用程序代码即可发出本指南后文所指定的 FTP 函数调用。 在生成过程中,应用程序还必须包含 nx_ftp_client.c 和 nx_ftp_server.c。 这些文件必须采用与其他应用程序文件相同的方式进行编译,并且其对象窗体必须与应用程序文件一起链接。 这就是使用 NetX FTP 所需的一切。

注意

由于 FTP 利用 NetX TCP 服务,因此在使用 FTP 之前,必须通过 nx_tcp_enable 调用启用 TCP。

小型示例系统

下面的图 1.1 举例说明了 NetX FTP 是多么易于使用。

注意

此示例适用于具有单个网络接口的主机设备。

在此示例中,FTP 包含文件 nx_ftp_client.h 和 nx_ftp_server.h 分别在第 10 行和第 11 行引入。 接下来,在第 134 行的“tx_application_define”中创建 FTP 服务器。 请注意,FTP 服务器控制块“Server”以前在第 31 行定义为全局变量。 创建成功后,将在第 363 行启动 FTP 服务器。 在第 183 行创建 FTP 客户端。 最后,客户端在第 229 行写入文件,并在第 318 行读回文件。

/* This is a small demo of NetX FTP on the high-performance NetX TCP/IP stack. This demo
relies on ThreadX, NetX, and FileX to show a simple file transfer from the client
and then back to the server. */

#include     "tx_api.h"
#include     "fx_api.h"
#include     "nx_api.h"
#include     "nx_ftp_client.h"
#include     "nx_ftp_server.h"

#define     DEMO_STACK_SIZE     4096

/* Define the ThreadX, NetX, and FileX object control blocks... */

TX_THREAD          server_thread;
TX_THREAD          client_thread;
NX_PACKET_POOL     server_pool;
NX_IP              server_ip;
NX_PACKET_POOL     client_pool;
NX_IP              client_ip;
FX_MEDIA           ram_disk;

/* Define the NetX FTP object control blocks. */

NX_FTP_CLIENT     ftp_client;
NX_FTP_SERVER     ftp_server;

/* Define the counters used in the demo application... */

ULONG     error_counter = 0;

/* Define the memory area for the FileX RAM disk. */

UCHAR     ram_disk_memory[32000];
UCHAR     ram_disk_sector_cache[512];

#define FTP_SERVER_ADDRESS IP_ADDRESS(1,2,3,4)
#define FTP_CLIENT_ADDRESS IP_ADDRESS(1,2,3,5)

extern UINT _fx_media_format(FX_MEDIA *media_ptr, VOID (*driver)(FX_MEDIA *media),
                    VOID *driver_info_ptr, UCHAR *memory_ptr, UINT memory_size,
                    CHAR *volume_name, UINT number_of_fats, UINT directory_entries,
                    UINT hidden_sectors, ULONG total_sectors, UINT bytes_per_sector,
                    UINT sectors_per_cluster, UINT heads, UINT sectors_per_track);

/* Define the FileX and NetX driver entry functions. */
VOID     _fx_ram_driver(FX_MEDIA *media_ptr);

/* Replace the 'ram' driver with your own Ethernet driver. */
VOID     _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);

void     client_thread_entry(ULONG thread_input);
void     thread_server_entry(ULONG thread_input);

/* Define server login/logout functions. These are stubs for functions that would
validate a client login request. */

UINT     server_login(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr,
                ULONG client_ip_address, UINT client_port, CHAR *name,
                CHAR *password, CHAR *extra_info);

UINT     server_logout(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr,
                    ULONG client_ip_address, UINT client_port, CHAR *name,
                    CHAR *password, CHAR *extra_info);

/* Define main entry point. */

int main()
{

    /* Enter the ThreadX kernel. */
    tx_kernel_enter();
    return(0);
}

/* Define what the initial system looks like. */

void     tx_application_define(void *first_unused_memory)
{

UINT      status;
UCHAR     *pointer;

    /* Setup the working pointer. */
    pointer = (UCHAR *) first_unused_memory;

    /* Create a helper thread for the server. */
    tx_thread_create(&server_thread, "FTP Server thread", thread_server_entry,
                    0, pointer, DEMO_STACK_SIZE,
                    4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);

    pointer = pointer + DEMO_STACK_SIZE;

    /* Initialize NetX. */
    nx_system_initialize();

    /* Create the packet pool for the FTP Server. */
    status = nx_packet_pool_create(&server_pool, "NetX Server Packet Pool",
                                    256, pointer, 8192);
    pointer = pointer + 8192;

    /* Check for errors. */
    if (status)
        error_counter++;

    /* Create the IP instance for the FTP Server. */
    status = nx_ip_create(&server_ip, "NetX Server IP Instance",
                        FTP_SERVER_ADDRESS, 0xFFFFFF00UL, &server_pool,
                        _nx_ram_network_driver, pointer, 2048, 1);
    pointer = pointer + 2048;

    /* Check status. */
    if (status != NX_SUCCESS)
    {
        error_counter++;
        return;
    }

    /* Enable ARP and supply ARP cache memory for server IP instance. */
    nx_arp_enable(&server_ip, (void *) pointer, 1024);
    pointer = pointer + 1024;

    /* Enable TCP. */
    nx_tcp_enable(&server_ip);

    /* Create the FTP server. */
    status = nx_ftp_server_create(&ftp_server, "FTP Server Instance",
                    &server_ip, &ram_disk, pointer, DEMO_STACK_SIZE,
                    &server_pool, server_login, server_logout);
    pointer = pointer + DEMO_STACK_SIZE;

    /* Check status. */
    if (status != NX_SUCCESS)
    {
        error_counter++;
        return;
    }

    /* Now set up the FTP Client. */

    /* Create the main FTP client thread. */
    status = tx_thread_create(&client_thread, "FTP Client thread ",
                            client_thread_entry, 0,
                            pointer, DEMO_STACK_SIZE,
                            6, 6, TX_NO_TIME_SLICE, TX_AUTO_START);
    pointer = pointer + DEMO_STACK_SIZE;

    /* Check status. */
    if (status != NX_SUCCESS)
    {
        error_counter++;
        return;
    }

    /* Create a packet pool for the FTP client. */
    status = nx_packet_pool_create(&client_pool, "NetX Client Packet Pool",
                                    256, pointer, 8192);
    pointer = pointer + 8192;

    /* Create an IP instance for the FTP client. */
    status = nx_ip_create(&client_ip, "NetX Client IP Instance", FTP_CLIENT_ADDRESS,
            0xFFFFFF00UL, &client_pool, _nx_ram_network_driver, pointer, 2048, 1);
    pointer = pointer + 2048;

    /* Enable ARP and supply ARP cache memory for the FTP Client IP. */
    nx_arp_enable(&client_ip, (void *) pointer, 1024);

    pointer = pointer + 1024;

    /* Enable TCP for client IP instance. */
    nx_tcp_enable(&client_ip);

    return;
}

/* Define the FTP client thread. */
void     client_thread_entry(ULONG thread_input)
{

NX_PACKET     *my_packet;
UINT          status;

    /* Format the RAM disk - the memory for the RAM disk was defined above. */
    status = _fx_media_format(&ram_disk,
            _fx_ram_driver, /* Driver entry */
            ram_disk_memory, /* RAM disk memory pointer */
            ram_disk_sector_cache, /* Media buffer pointer */
            sizeof(ram_disk_sector_cache), /* Media buffer size */
            "MY_RAM_DISK", /* Volume Name */
            1, /* Number of FATs */
            32, /* Directory Entries */
            0, /* Hidden sectors */
            256, /* Total sectors */
            128, /* Sector size */
            1, /* Sectors per cluster */
            1, /* Heads */
            1); /* Sectors per track */

    /* Check status. */
    if (status != NX_SUCCESS)
    {
        error_counter++;
        return;
    }

    /* Open the RAM disk. */
    status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory,
                            ram_disk_sector_cache, sizeof(ram_disk_sector_cache));

    /* Check status. */
    if (status != NX_SUCCESS)
    {
        error_counter++;
        return;
    }

     /* Let the IP threads and driver initialize the system. */
    tx_thread_sleep(100);

    /* Create an FTP client. */
    status = nx_ftp_client_create(&ftp_client, "FTP Client", &client_ip, 2000, &client_pool);

    /* Check status. */
    if (status != NX_SUCCESS)
    {

        error_counter++;
        return;
    }

    printf("Created the FTP Client\n");

    /* Now connect with the NetX FTP (IPv4) server. */
    status = nx_ftp_client_connect(&ftp_client, FTP_SERVER_ADDRESS,
                                    "name", "password", 100);

    /* Check status. */
    if (status != NX_SUCCESS)
    {

        error_counter++;
        return;
    }

    printf("Connected to the FTP Server\n");

    /* Open a FTP file for writing. */
    status = nx_ftp_client_file_open(&ftp_client, "test.txt", NX_FTP_OPEN_FOR_WRITE, 100);

    /* Check status. */
    if (status != NX_SUCCESS)
    {

        error_counter++;
        return;
    }

    printf("Opened the FTP client test.txt file\n");

    /* Allocate a FTP packet. */
    status = nx_packet_allocate(&client_pool, &my_packet, NX_TCP_PACKET, 100);

    /* Check status. */
    if (status != NX_SUCCESS)
    {

        error_counter++;
        return;
    }

    /* Write ABCs into the packet payload! */
    memcpy(my_packet -> nx_packet_prepend_ptr, "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", 28);

    /* Adjust the write pointer. */
    my_packet -> nx_packet_length = 28;
    my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + 28;

    /* Write the packet to the file test.txt. */
    status = nx_ftp_client_file_write(&ftp_client, my_packet, 100);

    /* Check status. */
    if (status != NX_SUCCESS)
    {
        error_counter++;
    }
    else
        printf("Wrote to the FTP client test.txt file\n");

    /* Close the file. */
    status = nx_ftp_client_file_close(&ftp_client, 100);

    /* Check status. */
    if (status != NX_SUCCESS)
        error_counter++;
    else
        printf("Closed the FTP client test.txt file\n");

    /* Now open the same file for reading. */
    status = nx_ftp_client_file_open(&ftp_client, "test.txt", NX_FTP_OPEN_FOR_READ, 100);

    /* Check status. */
    if (status != NX_SUCCESS)
        error_counter++;

    else
        printf("Reopened the FTP client test.txt file\n");

    /* Read the file. */
    status = nx_ftp_client_file_read(&ftp_client, &my_packet, 100);

    /* Check status. */
    if (status != NX_SUCCESS)
        error_counter++;
    else
    {
        printf("Reread the FTP client test.txt file\n");
        nx_packet_release(my_packet);
    }

    /* Close this file. */
    status = nx_ftp_client_file_close(&ftp_client, 100);

    if (status != NX_SUCCESS)
        error_counter++;

    /* Disconnect from the server. */
    status = nx_ftp_client_disconnect(&ftp_client, 100);

    /* Check status. */
    if (status != NX_SUCCESS)
        error_counter++;

    /* Delete the FTP client. */
    status = nx_ftp_client_delete(&ftp_client);

    /* Check status. */
    if (status != NX_SUCCESS)
        error_counter++;
}

/* Define the helper FTP server thread. */
void     thread_server_entry(ULONG thread_input)
{

UINT     status;

    /* Wait till the IP thread and driver have initialized the system. */
    tx_thread_sleep(100);

    /* OK to start the FTP Server. */
    status = nx_ftp_server_start(&ftp_server);

    if (status != NX_SUCCESS)
        error_counter++;

    printf("Server started!\n");

    /* FTP server ready to take requests! */

    /* Let the IP threads execute. */
    tx_thread_relinquish();

    return;
}

UINT     server_login(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr,
                ULONG client_ip_address, UINT client_port,
                CHAR *name, CHAR *password, CHAR *extra_info)
{

    printf("Logged in!\n");
    /* Always return success. */
    return(NX_SUCCESS);
}

UINT     server_logout(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr,
                    ULONG client_ip_address, UINT client_port,
                    CHAR *name, CHAR *password, CHAR *extra_info)
{
    printf("Logged out!\n");

    /* Always return success. */
    return(NX_SUCCESS);
}

图 1.1 NetX FTP 客户端和服务器的示例(单网络接口主机)

配置选项

有多个配置选项用于生成 NetX FTP。 以下列表详细介绍了每个配置选项:

  • NX_FTP_SERVER_PRIORITY:FTP 服务器线程的优先级。 默认情况下,此值定义为 16,表示将优先级指定为 16。

  • NX_FTP_MAX_CLIENTS:服务器可同时处理的最大客户端数。 默认情况下,此值为 4,表示同时支持 4 个客户端。

  • NX_FTP_SERVER_MIN_PACKET_PAYLOAD:服务器数据包池有效负载的最小大小(以字节为单位),包括 TCP、IP 和网络帧标头以及 HTTP 数据。 默认值为 256(FileX 中的最大文件名长度为)+ 12 个字节(用于存储文件信息)+ NX_PHYSICAL_TRAILER。

  • NX_FTP_NO_FILEX:如果定义了此选项,则可为 FileX 依赖项提供存根。 如果定义了此选项,则无需进行任何更改,FTP 客户端即可正常工作。 FTP 服务器将需要进行修改,或者用户必须创建几个 FileX 服务,FTP 服务器才能正常工作。

  • NX_FTP_CONTROL_TOS:FTP TCP 控制请求所需的服务类型。 默认情况下,此值定义为 NX_IP_NORMAL,表示正常的 IP 数据包服务。 此定义可以在包含 nx_ftp.h 之前由应用程序进行设置。

  • NX_FTP_DATA_TOS:FTP TCP 数据请求所需的服务类型。 默认情况下,此值定义为 NX_IP_NORMAL,表示正常的 IP 数据包服务。 此定义可以在包含 nx_ftp.h 之前由应用程序进行设置。

  • NX_FTP_FRAGMENT_OPTION:为 FTP TCP 请求启用分段。 默认情况下,此值为 NX_DONT_FRAGMENT,表示禁用 FTP TCP 分段。 此定义可以在包含 nx_ftp.h 之前由应用程序进行设置。

  • NX_FTP_CONTROL_WINDOW_SIZE:控制套接字窗口大小。 默认情况下,此值为 400 个字节。 此定义可以在包含 nx_ftp.h 之前由应用程序进行设置。

  • NX_FTP_DATA_WINDOW_SIZE:数据套接字窗口大小。 默认情况下,此值为 2048 个字节。 此定义可以在包含 nx_ftp.h 之前由应用程序进行设置。

  • NX_FTP_TIME_TO_LIVE:指定数据包在被丢弃之前可通过的路由器数目。 默认值设置为 0x80,但在包含 nx_ftp.h 之前可以重新定义该值。

  • NX_FTP_SERVER_TIMEOUT:指定内部服务将暂停的 ThreadX 时钟周期数。 默认值设置为 100,但在包含 nx_ftp.h 之前可以重新定义该值。

  • NX_FTP_USERNAME_SIZE:指定客户端提供的 username 中允许的字节数。 默认值设置为 20,但在包含 nx_ftp.h 之前可以重新定义该值。

  • NX_FTP_PASSWORD_SIZE:指定客户端提供的 password 中允许的字节数。 默认值设置为 20,但在包含 nx_ftp.h 之前可以重新定义该值。

  • NX_FTP_ACTIVITY_TIMEOUT:指定不活动时保持客户端连接的秒数。 默认值设置为 240,但在包含 nx_ftp.h 之前可以重新定义该值。

  • NX_FTP_TIMEOUT_PERIOD:指定服务器两次检查客户端非活动状态之间间隔的秒数。 默认值设置为 60,但在包含 nx_ftp.h 之前可以重新定义该值。