女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

第十八章 W55MH32 FTP_Server示例

W55MH32 ? 來源:W55MH32 ? 作者:W55MH32 ? 2025-07-24 11:55 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

單芯片解決方案,開啟全新體驗——W55MH32 高性能以太網單片機

W55MH32是WIZnet重磅推出的高性能以太網單片機,它為用戶帶來前所未有的集成化體驗。這顆芯片將強大的組件集于一身,具體來說,一顆W55MH32內置高性能Arm? Cortex-M3核心,其主頻最高可達216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲與數據處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協議棧、內置MAC以及PHY,擁有獨立的32KB以太網收發緩存,可供8個獨立硬件socket使用。如此配置,真正實現了All-in-One解決方案,為開發者提供極大便利。

在封裝規格上,W55MH32提供了兩種選擇:QFN100和QFN68。

W55MH32L采用QFN100封裝版本,尺寸為12x12mm,其資源豐富,專為各種復雜工控場景設計。它擁有66個GPIO、3個ADC、12通道DMA、17個定時器、2個I2C、5個串口、2個SPI接口(其中1個帶I2S接口復用)、1個CAN、1個USB2.0以及1個SDIO接口。如此豐富的外設資源,能夠輕松應對工業控制中多樣化的連接需求,無論是與各類傳感器、執行器的通信,還是對復雜工業協議的支持,都能游刃有余,成為復雜工控領域的理想選擇。同系列還有QFN68封裝的W55MH32Q版本,該版本體積更小,僅為8x8mm,成本低,適合集成度高的網關模組等場景,軟件使用方法一致。更多信息和資料請進入http://www.w5500.com/網站或者私信獲取。

此外,本W55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應用,涵蓋TCP SSL、HTTP SSL以及 MQTT SSL等,為網絡通信安全再添保障。

為助力開發者快速上手與深入開發,基于W55MH32L這顆芯片,WIZnet精心打造了配套開發板。開發板集成WIZ-Link芯片,借助一根USB C口數據線,就能輕松實現調試、下載以及串口打印日志等功能。開發板將所有外設全部引出,拓展功能也大幅提升,便于開發者全面評估芯片性能。

若您想獲取芯片和開發板的更多詳細信息,包括產品特性、技術參數以及價格等,歡迎訪問官方網頁:http://www.w5500.com/,我們期待與您共同探索W55MH32的無限可能。

wKgZO2iBiBmAe3DyAACpGc5mWX8613.png

第十八章 W55MH32 FTP_Server示例

本篇文章,我們將詳細介紹如何在W55MH32芯片上實現FTP協議。并通過實戰例程,為大家講解使用W55MH32作為FTP服務器、PC端作為FTP客戶端進行文件傳輸、目錄操作等多種功能。

該例程用到的其他網絡協議,例如DHCP請參考相關章節。有關W55MH32的初始化過程,請參考Network Install章節,這里將不再贅述。

1 FTP協議簡介

FTP(File Transfer Protocol,文件傳輸協議)是一種標準的網絡協議,用于在客戶端和服務器之間傳輸文件。FTP客戶端協議是基于 FTP協議實現的,用來指導客戶端如何與 FTP服務器通信,實現文件的上傳、下載、目錄操作等功能。由于 FTP最初是以明文傳輸設計的,不夠安全,在 FTP上加入 SSL/TLS加密層,可提供加密的控制連接和數據連接。以下是 FTP客戶端協議的主要內容和工作機制的介紹。

2 FTP協議特點

基于 TCP傳輸:FTP使用兩個 TCP連接:控制連接(端口 21)和數據連接(端口 20或 PASV模式動態分配的端口),確保可靠的數據傳輸。

分離控制與數據:

控制連接用于發送命令和接收響應。

數據連接用于文件內容或目錄信息的傳輸。

支持多種傳輸模式:

主動模式(Active Mode):服務器主動連接客戶端的數據端口。

被動模式(Passive Mode):客戶端主動連接服務器提供的數據端口,解決 NAT防火墻限制。

支持多種文件操作:

文件上傳(STOR)、下載(RETR)、刪除(DELE)。

目錄操作(MKD、RMD、CWD、PWD)。

獲取文件列表(LIST、NLST)。

明文傳輸(傳統 FTP):用戶名、密碼及數據以明文形式傳輸,不安全。安全改進:FTPS(FTP Secure,基于 SSL/TLS)和 SFTP(Secure File Transfer Protocol,基于 SSH)。

靈活的用戶認證機制:

支持匿名登錄(匿名用戶可通過 email作為密碼)。

支持認證用戶名和密碼。

3 FTP協議應用場景

接下來,我們了解下在W55MH32上,可以使用FTP協議完成哪些操作及應用呢?

固件升級嵌入式設備通過 FTP下載新固件或軟件更新包進行系統升級。適用于需要定期更新功能的設備,如路由器、工業控制設備等。

數據采集與傳輸:嵌入式設備(如傳感器節點或數據記錄器)將采集的數據上傳至遠程服務器進行存儲和分析。例如:環境監測設備將溫濕度數據上傳到服務器。

遠程配置與日志管理:設備通過 FTP下載配置文件或上傳日志信息供管理員分析和排錯。適用于工業自動化設備和嵌入式監控系統。

嵌入式 Web服務器的文件管理:許多嵌入式設備內置簡易 Web服務器,用于文件存儲或內容分發,通過 FTP管理這些文件資源。

4 FTP協議基本工作流程

1.建立控制連接

客戶端初始化:客戶端啟動 FTP客戶端程序,指定要連接的 FTP服務器的地址和端口號(端口號為 21)。

TCP連接建立:客戶端通過 TCP協議向服務器的 21端口發起連接請求。服務器監聽該端口,接收到請求后,與客戶端建立起一條 TCP連接,這個連接被稱為控制連接,主要用于傳輸 FTP命令和服務器的響應信息。

身份驗證:連接建立后,服務器會提示客戶端輸入用戶名和密碼進行身份驗證。客戶端發送相應的用戶名和密碼信息到服務器,服務器驗證通過后,才允許客戶端進行后續操作。也有一些匿名 FTP服務器,允許用戶以“anonymous”作為用戶名,以電子郵件地址作為密碼進行登錄,提供公開的文件訪問服務。

2.傳輸模式選擇

客戶端和服務器在控制連接上協商數據傳輸模式,主要有兩種模式:

主動模式(PORT模式):客戶端通過控制連接告訴服務器自己的數據端口(客戶端隨機開放的一個端口),服務器使用 20端口主動連接客戶端的數據端口來傳輸數據。

被動模式(PASV模式):客戶端發送 PASV命令給服務器,服務器在控制連接上告知客戶端自己開放的一個臨時數據端口(通常是 1024以上的端口),然后客戶端使用自己的一個隨機端口連接服務器的這個臨時數據端口來傳輸數據。

3.數據傳輸

根據用戶的操作需求,通過數據連接進行文件或目錄相關操作:

上傳文件:客戶端向服務器發送 STOR(存儲)命令,然后通過數據連接將本地文件數據發送到服務器。服務器接收到數據后,將其存儲在指定的目錄下。

下載文件:客戶端向服務器發送 RETR(檢索)命令,請求下載服務器上的文件。服務器通過數據連接將文件數據發送給客戶端,客戶端接收數據并將其保存到本地指定位置。

目錄操作:客戶端還可以發送諸如 LIST(列出目錄內容)、CWD(更改工作目錄)、MKD(創建目錄)、RMD(刪除目錄)等命令,服務器執行相應操作,并通過控制連接返回操作結果。執行這些命令時,若需要傳輸目錄列表等數據,也會通過數據連接進行傳輸。

4.關閉連接

數據連接關閉:在完成文件傳輸或其他操作后,數據連接會被關閉。如果還有其他操作需要進行,客戶端和服務器可以根據需要重新建立數據連接。

控制連接關閉:當客戶端完成所有操作后,會向服務器發送 QUIT命令,服務器接收到該命令后,會關閉控制連接。至此,客戶端與服務器之間的 FTP會話結束。

5主動模式與被動模式詳解

主動模式(Active Mode):

客戶端打開一個端口并監聽。

客戶端通過控制連接告訴服務器自己的 IP和端口。

服務器主動連接到客戶端指定的端口傳輸數據。

被動模式(Passive Mode):

客戶端通過控制連接請求被動模式。

服務器打開一個隨機端口并通過控制連接告知客戶端。

客戶端主動連接到服務器指定的端口傳輸數據。

優缺點對比:

主動模式更適合在服務器端網絡無防火墻限制的環境。

被動模式更適合客戶端在 NAT或防火墻后的情況。

6 FTP報文解析

FTP 報文分為命令和響應報文,命令報文用于發送操作請求,響應報文用于返回結果。

命令報文格式為“<命令> <參數>rn”,字段解釋如下:

<命令>:FTP命令(如 USER、PASS)。

<參數>:命令的附加信息(如用戶名、文件名)。

例如“USER usernamern”。常見的命令包括登錄 (USER, PASS)、文件操作 (RETR, STOR)、目錄操作 (LIST, CWD) 等。每個 FTP報文由命令或響應代碼、狀態碼及附加數據組成,狀態碼用于指示操作結果。

以下是 FTP常見命令:

USER:提供用戶名進行身份驗證。

PASS:提供密碼進行身份驗證。

CWD:更改當前工作目錄。

PWD:顯示當前工作目錄。

LIST:列出目錄下的文件和子目錄。

RETR:從服務器下載文件。

STOR:上傳文件到服務器。

DELE:刪除指定文件。

MKD:創建新目錄。

RMD:刪除目錄。

QUIT:終止會話并退出。

TYPE:設置文件傳輸類型(ASCII或 Binary)。

PORT:指定數據連接的端口。

PASV:啟用被動模式,服務器指定端口供客戶端連接。

響應報文格式為“<狀態碼> <說明文字>rn”,字段解釋如下:

<狀態碼>:三位數字表示狀態。

<說明文字>:狀態的文字描述。

例如“230 User logged in, proceed.rn”。以下是FTP常見的響應碼:

1xx(信息性響應):主要是提供一些初步的信息,通常表示服務器正在處理請求,還沒有完成操作。

2xx(成功響應):表示命令成功執行。這是客戶端最希望看到的響應類型之一,說明請求的操作(如登錄、文件傳輸等)順利完成。

3xx(補充信息響應):表示服務器需要一些額外的信息才能完成操作。通常是在身份驗證或者文件定位等過程中出現。

4xx(暫時錯誤響應):表示客戶端的請求有問題,但錯誤是暫時的,可能通過一些調整(如重新發送請求等)可以解決。

5xx(永久性錯誤響應):表示客戶端的請求存在錯誤,并且這個錯誤是比較嚴重的,很難通過簡單的調整來糾正。

接著我們來看看FTP獲取目錄的報文示例:

客戶端建立TCP連接到服務器的21端口

服務器返回:220 Welcome to FTP Serverrn

客戶端發送:USER wiznetrn

服務器返回:331 User wiznet OK.Password requiredrn

客戶端發送:PASS wiznetrn

服務器返回:230 User logged inrn

客戶端發送PORT 192,168,1,5,20,100rn(主動模式,192,168,1,5是客戶端的地址,20,100是客戶端期望的端口號20*256+100=5260)

服務器返回:200 PORT command successfulrn

客戶端發送:LISTrn(DIR命令,獲取當前目錄的文件信息)

服務器回復:150 Opening ASCII mode data connection for file listrn

服務器像客戶端期望的端口號發起TCP連接,并傳輸目錄信息,傳輸完成后關閉TCP連接。

客戶端發送:QUITrn(退出FTP會話)

服務器回復:221 Goodbyern

7實現過程

接下來,我們看看如何在W55MH32上實現FTP協議的Server模式。

注意:測試實例需要PC端和W55MH32處于同一網段。

步驟一:獲取網絡配置信息和FTP初始化

wizchip_getnetinfo(&net_info);
ftpd_init(net_info.ip);

ftpd_init()函數內容如下:

/**
* @brief Initialize the FTP server
*
* Initialize the FTP server, set the status, commands, modes and other parameters of the FTP server, and initialize the FTP login username and password.
*
* @param src_ip: Source IP address
*/
void ftpd_init(uint8_t *src_ip)
{
   ftp.state       = FTPS_NOT_LOGIN;
   ftp.current_cmd = NO_CMD;
   ftp.dsock_mode  = ACTIVE_MODE;
   ftp.ID_Enable = STATUS_USED;
   ftp.PW_Enable = STATUS_USED;
   if (ftp.ID_Enable == STATUS_USED)
   {
       strcpy(ftp.username, ftp_ID);
       printf(" FTP ID[%d]:%s rn", strlen(ftp.username), ftp.username);
   }
   if (ftp.PW_Enable == STATUS_USED)
   {
       strcpy(ftp.userpassword, ftp_PW);
       printf(" FTP PW[%d]:%s rn", strlen(ftp.userpassword), ftp.userpassword);
   }
   local_ip.cVal[0] = src_ip[0];
   local_ip.cVal[1] = src_ip[1];
   local_ip.cVal[2] = src_ip[2];
   local_ip.cVal[3] = src_ip[3];
   local_port       = 35000;
   strcpy(ftp.workingdir, "/");
   socket(CTRL_SOCK, Sn_MR_TCP, IPPORT_FTP, 0x0);
   socket(CTRL_SOCK1, Sn_MR_TCP, IPPORT_FTP, 0x0);
}

ftpd_init()函數的主要作用是對 FTP服務器的各種參數進行初始化設置,包括服務器狀態、用戶認證信息、網絡地址和端口,以及創建TCP socket,為后續的 FTP服務運行做好準備。

步驟二:實現服務器和客戶端之間的持續交互

ftpd_run()函數在主循環中不斷被調用,作用是讓 FTP服務器持續運行,不斷處理客戶端的各種請求,實現服務器與客戶端之間的持續交互,以提供穩定的 FTP服務 。

while (1)
{
 ftpd_run(ethernet_buf);
}

ftpd_run()函數內容如下:

c

運行

uint8_t ftpd_run(uint8_t *dbuf)
{
    uint16_t size = 0;
    long     ret = 0;
    uint32_t blocklen, recv_byte;
    uint32_t remain_filesize;
    int32_t  remain_datasize;
#if defined(F_FILESYSTEM)
    FILINFO fno;
#endif

    // FTP Control 1
#if 1
    switch (getSn_SR(CTRL_SOCK))
    {
        case SOCK_ESTABLISHED:
            if (!connect_state_control)
            {
#if defined(_FTP_DEBUG_)
                printf("%d:FTP Connectedrn", CTRL_SOCK);
#endif
                // fsprintf(CTRL_SOCK, banner, HOSTNAME, VERSION);
                strcpy(ftp.workingdir, "/");
                sprintf((char *)dbuf, "220 %s FTP version %s ready.rn", HOSTNAME, VERSION);
                ret = send(CTRL_SOCK, (uint8_t *)dbuf, strlen((const char *)dbuf));

#if defined(_FTP_DEBUG_)
                printf("%d:send() [%s]rn", CTRL_SOCK, dbuf);
#endif
                if (ret < 0)
                {
#if defined(_FTP_DEBUG_)
                    printf("%d:send() error:%ldrn", CTRL_SOCK, ret);
#endif
                    close(CTRL_SOCK);
                    return ret;
                }
                connect_state_control = 1;
            }
#if connect_timeout_en
            else
            {
                if (con_remain_cnt1 > remain_time)
                {
                    if ((ret = disconnect(CTRL_SOCK)) != SOCK_OK)
                        return ret;
#if defined(_FTP_DEBUG_)
                    printf("%d:Timeout Closedrn", CTRL_SOCK);
#endif
                }
#if defined(_FTP_DEBUG_)
                else if (((con_remain_cnt1 % 10000) == 0) && (con_remain_cnt1 != 0))
                {
                    // printf("%d:Timeout Count:%ldrn", CTRL_SOCK, con_remain_cnt1);
                }
#endif
                con_remain_cnt1++;
            }
#endif

#if defined(_FTP_DEBUG_)
            // printf("ftp socket %drn", CTRL_SOCK);
#endif

            if ((size = getSn_RX_RSR(CTRL_SOCK)) > 0)  // Don't need to check SOCKERR_BUSY because it doesn't not occur.
            {
#if defined(_FTP_DEBUG_)
                printf("%d:size: %drn", CTRL_SOCK, size);
#endif

                memset(dbuf, 0, _MAX_SS);

                if (size > _MAX_SS)
                    size = _MAX_SS - 1;

                ret      = recv(CTRL_SOCK, dbuf, size);
                dbuf[ret] = '';
                if (ret != size)
                {
                    if (ret == SOCK_BUSY)
                        return 0;
                    if (ret < 0)
                    {
#if defined(_FTP_DEBUG_)
                        printf("%d:recv() error:%ldrn", CTRL_SOCK, ret);
#endif
                        close(CTRL_SOCK);
                        return ret;
                    }
                }
#if defined(_FTP_DEBUG_)
                printf("%d:Rcvd Command: %s", CTRL_SOCK, dbuf);
#endif
                proc_ftpd(CTRL_SOCK, (char *)dbuf);
                con_remain_cnt1 = 0;
            }
            break;

        case SOCK_CLOSE_WAIT:
#if defined(_FTP_DEBUG_)
            printf("%d:CloseWaitrn", CTRL_SOCK);
#endif
            if ((ret = disconnect(CTRL_SOCK)) != SOCK_OK)
                return ret;
#if defined(_FTP_DEBUG_)
            printf("%d:Closedrn", CTRL_SOCK);
#endif
            break;

        case SOCK_CLOSED:
#if defined(_FTP_DEBUG_)
            printf("%d:FTPStartrn", CTRL_SOCK);
#endif
            if ((ret = socket(CTRL_SOCK, Sn_MR_TCP, IPPORT_FTP, 0x0)) != CTRL_SOCK)
            {
#if defined(_FTP_DEBUG_)
                printf("%d:socket() error:%ldrn", CTRL_SOCK, ret);
#endif
                close(CTRL_SOCK);
                return ret;
            }
            break;

        case SOCK_INIT:
#if defined(_FTP_DEBUG_)
            printf("%d:Openedrn", CTRL_SOCK);
#endif
            strcpy(ftp.workingdir, "/");
            if ((ret = listen(CTRL_SOCK)) != SOCK_OK)
            {
#if defined(_FTP_DEBUG_)
                printf("%d:Listen errorrn", CTRL_SOCK);
#endif
                return ret;
            }
            connect_state_control = 0;
            con_remain_cnt1       = 0;

#if defined(_FTP_DEBUG_)
            printf("%d:Listen okrn", CTRL_SOCK);
#endif
            break;

        default:
            break;
    }
#endif

進入ftpd_run()函數后,程序會執行一個TCP Server模式的狀態機(具體可參考TCP Server章節),當socket處于SOCK_ESTABLISHED狀態時,如果是首次進入SOCK_ESTABLISHED狀態,則會向客戶端發送歡迎消息。后續則是監聽客戶端指令,當收到客戶端指令后,會進入proc_ftpd()進行處理。

proc_ftpd()函數處理 FTP服務的命令,根據不同命令及參數進行相應操作,包括用戶認證、文件操作、數據傳輸、狀態處理及錯誤響應。

注意:當宏定義connect_timeout_en的值設置為 1時,會啟用連接超時功能。如果在超過宏定義remain_time所設定的時長后,仍然沒有進行任何操作,系統將自動斷開連接。其中,connect_timeout_en是一個控制連接超時功能開啟或關閉的宏,其值為 1表示開啟該功能,為 0表示關閉;而remain_time是一個宏,它定義了在觸發自動斷開連接操作前的最大允許無操作時長。

proc_ftpd()函數如下:

 /**
* Processes FTP-related data or request.
*
* @param sn   Identifier for distinguishing requests/sessions.
* @param buf  Buffer to store result or status information.
*
* @return Character indicating operation status ('S' for success, 'E' for error, etc.).
*
* Note: Refer to documentation for exact behavior and meaning of return value.
*/
char proc_ftpd(uint8_t sn, char *buf)
{
   char **cmdp, *cp, *arg, *tmpstr;
   char   sendbuf[200];
   int    slen;
   long   ret;
   // Translate first word to lower case
   for (cp = buf; *cp != ' ' && *cp != ''; cp++)
       *cp = tolower(*cp);
   // Find command in table; if not present, return syntax error
   for (cmdp = commands; *cmdp != NULL; cmdp++)
       if (strncmp(*cmdp, buf, strlen(*cmdp)) == 0)
           break;
   if (*cmdp == NULL)
   {
       // fsprintf(CTRL_SOCK, badcmd, buf);
       slen = sprintf(sendbuf, "500 Unknown command '%s'rn", buf);
       send(sn, (uint8_t *)sendbuf, slen);
       return 0;
   }
   // Allow only USER, PASS and QUIT before logging in
   if (ftp.state == FTPS_NOT_LOGIN)
   {
       switch (cmdp - commands)
       {
       case USER_CMD:
       case PASS_CMD:
       case QUIT_CMD:
           break;
       default:
           // fsprintf(CTRL_SOCK, notlog);
           slen = sprintf(sendbuf, "530 Please log in with USER and PASSrn");
           send(sn, (uint8_t *)sendbuf, slen);
           return 0;
       }
   }
   arg = &buf[strlen(*cmdp)];
   while (*arg == ' ')
       arg++;
   /* Execute specific command */
   switch (cmdp - commands)
   {
   case USER_CMD:
#if defined(_FTP_DEBUG_)
       printf("USER_CMD : %s", arg);
#endif
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
       if (ftp.ID_Enable == STATUS_USED)
       {
           if (strcmp(ftp.username, arg) != 0)
           {
               slen = sprintf(sendbuf, "430 Invalid usernamern");
               ret  = send(sn, (uint8_t *)sendbuf, slen);
               if (ret < 0)
               {
#if defined(_FTP_DEBUG_)
                   printf("%d:send() error:%ldrn", sn, ret);
#endif
                   close(sn);
                   return ret;
               }
               break;
           }
       }
       else
       {
           strcpy(ftp.username, arg);
       }
       // fsprintf(CTRL_SOCK, givepass);
       slen = sprintf(sendbuf, "331 Enter PASS commandrn");
       ret  = send(sn, (uint8_t *)sendbuf, slen);
       if (ret < 0)
       {
#if defined(_FTP_DEBUG_)
           printf("%d:send() error:%ldrn", sn, ret);
#endif
           close(sn);
           return ret;
       }
       break;
   case PASS_CMD:
#if defined(_FTP_DEBUG_)
       printf("PASS_CMD : %s", arg);
#endif
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
       if (ftp.PW_Enable == STATUS_USED)
       {
           if (strcmp(ftp.userpassword, arg) != 0)
           {
               slen = sprintf(sendbuf, "430 Invalid passwordrn");
               ret  = send(sn, (uint8_t *)sendbuf, slen);
               if (ret < 0)
               {
#if defined(_FTP_DEBUG_)
                   printf("%d:send() error:%ldrn", sn, ret);
#endif
                   close(sn);
                   return ret;
               }
               break;
           }
       }
       ftplogin(sn, arg);
       break;
   case TYPE_CMD:
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
       switch (arg[0])
       {
       case 'A':
       case 'a': // Ascii
           ftp.type = ASCII_TYPE;
           // fsprintf(CTRL_SOCK, typeok, arg);
           slen = sprintf(sendbuf, "200 Type set to %srn", arg);
           send(sn, (uint8_t *)sendbuf, slen);
           break;
       case 'B':
       case 'b': // Binary
       case 'I':
       case 'i': // Image
           ftp.type = IMAGE_TYPE;
           // fsprintf(CTRL_SOCK, typeok, arg);
           slen = sprintf(sendbuf, "200 Type set to %srn", arg);
           send(sn, (uint8_t *)sendbuf, slen);
           break;
       default: /* Invalid */
           // fsprintf(CTRL_SOCK, badtype, arg);
           slen = sprintf(sendbuf, "501 Unknown type "%s"rn", arg);
           send(sn, (uint8_t *)sendbuf, slen);
           break;
       }
       break;
   case FEAT_CMD:
       slen = sprintf(sendbuf, "211-Features:rn MDTMrn REST STREAMrn SIZErn MLST size*;type*;create*;modify*;rn MLSDrn UTF8rn CLNTrn MFMTrn211 ENDrn");
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   case QUIT_CMD:
#if defined(_FTP_DEBUG_)
       printf("QUIT_CMDrn");
#endif
       // fsprintf(CTRL_SOCK, bye);
       slen = sprintf(sendbuf, "221 Goodbye!rn");
       send(sn, (uint8_t *)sendbuf, slen);
       disconnect(sn);
       break;
   case RETR_CMD:
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
#if defined(_FTP_DEBUG_)
       printf("RETR_CMDrn");
#endif
       if (strlen(ftp.workingdir) == 1)
           sprintf(ftp.filename, "/%s", arg);
       else
           sprintf(ftp.filename, "%s/%s", ftp.workingdir, arg);
       slen = sprintf(sendbuf, "150 Opening data channel for file downloand from server of "%s"rn", ftp.filename);
       send(sn, (uint8_t *)sendbuf, slen);
       ftp.current_cmd = RETR_CMD;
       break;
   case APPE_CMD:
   case STOR_CMD:
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
#if defined(_FTP_DEBUG_)
       printf("STOR_CMDrn");
#endif
       if (strlen(ftp.workingdir) == 1)
           sprintf(ftp.filename, "/%s", arg);
       else
           sprintf(ftp.filename, "%s/%s", ftp.workingdir, arg);
       slen = sprintf(sendbuf, "150 Opening data channel for file upload to server of "%s"rn", ftp.filename);
       send(sn, (uint8_t *)sendbuf, slen);
       ftp.current_cmd = STOR_CMD;
       if (ftp.dsock_mode == ACTIVE_MODE)
       {
           if ((ret = connect(DATA_SOCK, remote_ip.cVal, remote_port)) != SOCK_OK)
           {
#if defined(_FTP_DEBUG_)
               printf("%d:Connect errorrn", DATA_SOCK);
#endif
               return ret;
           }
       }
       connect_state_data = 0;
       break;
   case PORT_CMD:
#if defined(_FTP_DEBUG_)
       printf("PORT_CMDrn");
#endif
       if (pport(arg) == -1)
       {
           // fsprintf(CTRL_SOCK, badport);
           slen = sprintf(sendbuf, "501 Bad port syntaxrn");
           send(sn, (uint8_t *)sendbuf, slen);
       }
       else
       {
           // fsprintf(CTRL_SOCK, portok);
           ftp.dsock_mode  = ACTIVE_MODE;
           ftp.dsock_state = DATASOCK_READY;
           slen            = sprintf(sendbuf, "200 PORT command successful.rn");
           send(sn, (uint8_t *)sendbuf, slen);
       }
       break;
   case MLSD_CMD:
#if defined(_FTP_DEBUG_)
       printf("MLSD_CMDrn");
#endif
       slen = sprintf(sendbuf, "150 Opening data channel for directory listing of "%s"rn", ftp.workingdir);
       send(sn, (uint8_t *)sendbuf, slen);
       ftp.current_cmd = MLSD_CMD;
       break;
   case LIST_CMD:
#if defined(_FTP_DEBUG_)
       printf("LIST_CMDrn");
#endif
       slen = sprintf(sendbuf, "150 Opening data channel for directory listing of "%s"rn", ftp.workingdir);
       send(sn, (uint8_t *)sendbuf, slen);
       ftp.current_cmd = LIST_CMD;
       break;
   case NLST_CMD:
#if defined(_FTP_DEBUG_)
       printf("NLST_CMDrn");
#endif
       break;
   case SYST_CMD:
       slen = sprintf(sendbuf, "215 UNIX emulated by WIZnetrn");
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   case PWD_CMD:
   case XPWD_CMD:
       slen = sprintf(sendbuf, "257 "%s" is current directory.rn", ftp.workingdir);
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   case PASV_CMD:
       slen = sprintf(sendbuf, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)rn", local_ip.cVal[0], local_ip.cVal[1], local_ip.cVal[2], local_ip.cVal[3], local_port >> 8, local_port & 0x00ff);
       send(sn, (uint8_t *)sendbuf, slen);
       if (getSn_SR(DATA_SOCK) == SOCK_ESTABLISHED)
       {
#if defined(_FTP_DEBUG_)
           printf("data disconnect: %drn", DATA_SOCK);
#endif
           disconnect(DATA_SOCK);
       }
       ftp.dsock_mode  = PASSIVE_MODE;
       ftp.dsock_state = DATASOCK_READY;
       cur_sn          = sn;
#if defined(_FTP_DEBUG_)
       printf("PASV port: %drn", local_port);
#endif
       break;
   case SIZE_CMD:
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
       if (slen > 3)
       {
           tmpstr  = strrchr(arg, '/');
           *tmpstr = 0;
#if defined(F_FILESYSTEM)
           slen = get_filesize(arg, tmpstr + 1);
#else
           slen = _MAX_SS;
#endif
           if (slen > 0)
               slen = sprintf(sendbuf, "213 %drn", slen);
           else
               slen = sprintf(sendbuf, "550 File not Foundrn");
       }
       else
       {
           slen = sprintf(sendbuf, "550 File not Foundrn");
       }
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   case CWD_CMD:
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
       if (slen > 3)
       {
           arg[slen - 3] = 0x00;
           tmpstr        = strrchr(arg, '/');
           *tmpstr       = 0;
#if defined(F_FILESYSTEM)
           slen = get_filesize(arg, tmpstr + 1);
#else
           slen = 0;
#endif
           *tmpstr = '/';
           if (slen == 0)
           {
               slen = sprintf(sendbuf, "213 %drn", slen);
               strcpy(ftp.workingdir, arg);
               slen = sprintf(sendbuf, "250 CWD successful. "%s" is current directory.rn", ftp.workingdir);
           }
           else
           {
               slen = sprintf(sendbuf, "550 CWD failed. "%s"rn", arg);
           }
       }
       else
       {
           strcpy(ftp.workingdir, arg);
           slen = sprintf(sendbuf, "250 CWD successful. "%s" is current directory.rn", ftp.workingdir);
       }
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   case MKD_CMD:
   case XMKD_CMD:
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
#if defined(F_FILESYSTEM)
       if (f_mkdir(arg) != 0)
       {
           slen = sprintf(sendbuf, "550 Can't create directory. "%s"rn", arg);
       }
       else
       {
           slen = sprintf(sendbuf, "257 MKD command successful. "%s"rn", arg);
           // strcpy(ftp.workingdir, arg);
       }
#else
       slen = sprintf(sendbuf, "550 Can't create directory. Permission deniedrn");
#endif
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   case DELE_CMD:
       slen          = strlen(arg);
       arg[slen - 1] = 0x00;
       arg[slen - 2] = 0x00;
#if defined(F_FILESYSTEM)
       if (f_unlink(arg) != 0)
       {
           slen = sprintf(sendbuf, "550 Could not delete. "%s"rn", arg);
       }
       else
       {
           slen = sprintf(sendbuf, "250 Deleted. "%s"rn", arg);
       }
#else
       slen = sprintf(sendbuf, "550 Could not delete. Permission deniedrn");
#endif
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   case XCWD_CMD:
   case ACCT_CMD:
   case XRMD_CMD:
   case RMD_CMD:
   case STRU_CMD:
   case MODE_CMD:
   case XMD5_CMD:
       // fsprintf(CTRL_SOCK, unimp);
       slen = sprintf(sendbuf, "502 Command does not implemented yet.rn");
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   default: // Invalid
       // fsprintf(CTRL_SOCK, badcmd, arg);
       slen = sprintf(sendbuf, "500 Unknown command '%s'rn", arg);
       send(sn, (uint8_t *)sendbuf, slen);
       break;
   }
   return 1;
}

進入 proc_ftpd()函數后,程序會執行一個狀態機,首先將接收的命令轉換為小寫并在命令表中查找,未找到時發送錯誤信息。登錄前僅允許 USER、PASS、QUIT命令,其余報錯。對于不同命令,如 USER_CMD處理用戶名驗證和后續操作,PASS_CMD進行密碼驗證和登錄,TYPE_CMD處理傳輸類型設置,FEAT_CMD發送特性信息,QUIT_CMD斷開連接,還有 RETR_CMD等文件操作命令,以及 PORT_CMD、PASV_CMD等數據連接模式相關命令,根據不同情況執行相應的操作和錯誤處理,同時發送相應的狀態信息。

8運行結果

燒錄例程運行后,首先進行了PHY鏈路檢測,然后打印設置網絡信息。打開filezilla軟件(下載鏈接:客戶端 - FileZilla中文網),在filezilla軟件上填寫主機ID,用戶名,密碼,端口號(通常是21)連接FTP服務器。連接成功顯示如下界面:

wKgZPGiBrXaAS0MOAAB3tSsq8hk963.png

然后拉住本地站點文件向遠程站點(服務器)內拖動,成功向服務器傳輸文件。

wKgZPGiBrXaAErAhAAB09F2OWEc213.png

9總結

本文講解了如何在 W55MH32芯片上實現 FTP協議的服務器模式,通過實戰例程展示了使用 W55MH32作為 FTP服務器與 PC端進行文件傳輸、目錄操作等功能的過程,涵蓋獲取網絡配置信息和 FTP初始化、實現服務器和客戶端之間的持續交互等關鍵步驟。文章詳細介紹了 FTP協議的概念、特點、應用場景、基本工作流程、主動與被動模式、報文解析,幫助讀者理解其在文件傳輸中的實際應用價值。

下一篇文章將聚焦 FTP協議客戶端模式,解析其核心原理及在文件傳輸中的應用,同時講解如何在W55MH32上實現 FTP客戶端功能,敬請期待!

WIZnet是一家無晶圓廠半導體公司,成立于 1998年。產品包括互聯網處理器 iMCU?,它采用 TOE(TCP/IP卸載引擎)技術,基于獨特的專利全硬連線 TCP/IP。iMCU?面向各種應用中的嵌入式互聯網設備。

WIZnet在全球擁有 70多家分銷商,在香港、韓國、美國設有辦事處,提供技術支持和產品營銷。

香港辦事處管理的區域包括:澳大利亞、印度、土耳其、亞洲(韓國和日本除外)。

審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 以太網
    +關注

    關注

    41

    文章

    5684

    瀏覽量

    176251
  • 數據傳輸
    +關注

    關注

    9

    文章

    2024

    瀏覽量

    66139
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    第十八章 I2C通信測試

    本章介紹了I2C協議,其物理層用SDA和SCL雙線,支持多設備:協議層含起始/停止信號、應答機制等。還講解W55MH32的I2C外設及初始化,并進行了通信測試代碼的分析。
    的頭像 發表于 06-19 17:07 ?600次閱讀
    <b class='flag-5'>第十八章</b> I2C通信測試

    第二章 W55MH32 DHCP示例

    本文介紹 DHCP?協議,包括其在 IP?網絡自動分配參數的功能、便捷配置等特點、工作原理、報文格式和應用場景。通過 W55MH32?實戰例程展示動態獲取網絡地址信息過程,含注冊定時器中斷、啟用模式和獲取信息等步驟,燒錄后可完成檢測與信息打印,PC?端能 PING?通設備。
    的頭像 發表于 07-24 09:02 ?152次閱讀
    第二章 <b class='flag-5'>W55MH32</b> DHCP<b class='flag-5'>示例</b>

    第五章 W55MH32 UDP示例

    本文介紹了在 W55MH32?芯片上實現 UDP?通信及數據回環測試的方法。闡述了 UDP?協議的概念、特點、應用場景、報文傳輸流程和報文結構,展示了實現過程,借助網絡調試工具完成測試。
    的頭像 發表于 07-24 09:13 ?95次閱讀
    第五章 <b class='flag-5'>W55MH32</b> UDP<b class='flag-5'>示例</b>

    第九章 W55MH32 HTTP Server示例

    本文介紹了在 W55MH32?芯片上實現 HTTP Server?功能,并通過瀏覽器修改其網絡地址信息的方法。闡述了 HTTP?協議的概念、特點、應用場景、工作流程、請求方法、響應內容,以及 Web?頁面構成和交互方式。展示了在W55M
    的頭像 發表于 07-24 09:35 ?125次閱讀
    第九章 <b class='flag-5'>W55MH32</b> HTTP <b class='flag-5'>Server</b><b class='flag-5'>示例</b>

    第十W55MH32 SNTP示例

    本文講解了如何在W55MH32芯片上實現SNTP授時功能,通過實例詳細展示了從SNTP服務器同步時間的實現流程,包括時間請求、響應解析和本地時間校準等核心步驟。文章還對SNTP的應用場景進行了分析,幫助讀者理解其在時間同步中的實際應用價值。
    的頭像 發表于 07-24 09:43 ?159次閱讀
    <b class='flag-5'>第十</b>章 <b class='flag-5'>W55MH32</b> SNTP<b class='flag-5'>示例</b>

    第十一章 W55MH32 SMTP示例

    本文講解了如何在 W55MH32?芯片上實現 SMTP?協議,通過實例詳細展示了在該芯片上使用 SMTP?協議發送電子郵件的實現流程,包括 SMTP?發送內容初始化、使用 DNS?協議解析 SMTP
    的頭像 發表于 07-24 09:49 ?131次閱讀
    <b class='flag-5'>第十</b>一章 <b class='flag-5'>W55MH32</b> SMTP<b class='flag-5'>示例</b>

    第十二章 W55MH32 NetBIOS示例

    本文講解了如何在 W55MH32?芯片上實現 NetBIOS?功能,通過實戰例程展示了利用 NetBIOS?進行名稱 PING?測試的具體過程,包括 NetBIOS?功能的調用、請求處理、名稱解析
    的頭像 發表于 07-24 09:58 ?138次閱讀
    <b class='flag-5'>第十</b>二章 <b class='flag-5'>W55MH32</b> NetBIOS<b class='flag-5'>示例</b>

    第十三章 W55MH32 UPnP端口轉發示例

    本文講解了如何在 W55MH32?芯片上實現 UPnP?協議的端口轉發功能,通過實戰例程詳細展示了從設備搜索、獲取設備描述、訂閱事件到添加和刪除端口映射的完整流程,包括各步驟涉及的協議報文、函數實現
    的頭像 發表于 07-24 10:28 ?118次閱讀
    <b class='flag-5'>第十</b>三章 <b class='flag-5'>W55MH32</b> UPnP端口轉發<b class='flag-5'>示例</b>

    第十四章 W55MH32 TFTP示例

    本文講解了如何在 W55MH32?芯片上實現 TFTP?協議,通過實戰例程詳細展示了使用 TFTP?客戶端模式從服務器獲取文本文件的過程,涵蓋 TFTP?初始化、發送讀請求、運行協議并處理結果等核心
    的頭像 發表于 07-24 10:37 ?141次閱讀
    <b class='flag-5'>第十</b>四章 <b class='flag-5'>W55MH32</b> TFTP<b class='flag-5'>示例</b>

    第十五章 W55MH32 SNMP示例

    本文講解了如何在 W55MH32?芯片上實現 SNMP?功能,通過實戰例程展示了使用 MIB Browser?管理 W55MH32?的具體過程,涵蓋在 MIB Browser?中創建分支、添加葉子
    的頭像 發表于 07-24 10:43 ?150次閱讀
    <b class='flag-5'>第十</b>五章 <b class='flag-5'>W55MH32</b> SNMP<b class='flag-5'>示例</b>

    第十六章 W55MH32 PING示例

    本文講解了如何在 W55MH32?芯片上通過 IPRAW?模式實現 ICMP?協議中的 PING?命令,以進行網絡連通性測試,通過實戰例程展示了從發送 PING?請求、接收并解析回復到統計結果的完整
    的頭像 發表于 07-24 11:41 ?63次閱讀
    <b class='flag-5'>第十</b>六章 <b class='flag-5'>W55MH32</b> PING<b class='flag-5'>示例</b>

    第十九章 W55MH32 FTP_Client示例

    本文講解了如何在 W55MH32?芯片上實現 FTP?協議的客戶端模式,通過實戰例程展示了使用該客戶端模式訪問 FTP?服務器并下載文件的過程,涵蓋 FTP?客戶端模式初始化、在主循環
    的頭像 發表于 07-24 13:39 ?86次閱讀
    <b class='flag-5'>第十</b>九章 <b class='flag-5'>W55MH32</b> <b class='flag-5'>FTP</b>_Client<b class='flag-5'>示例</b>

    第二十六章 W55MH32?上位機搜索和配置示例

    本文講解了如何在 W55MH32?芯片上實現上位機搜索和配置功能,通過實戰例程展示了使用開源上位機配置工具 SmartConfigTool?搜索局域網中的 W55MH32?并進行網絡地址配置的過程
    的頭像 發表于 07-24 16:13 ?90次閱讀
    第二十六章 <b class='flag-5'>W55MH32</b>?上位機搜索和配置<b class='flag-5'>示例</b>

    第二十九章 W55MH32 Modbus_TCP_Server示例

    本文講解了如何在 W55MH32?芯片上實現 Modbus TCP?協議的服務器模式,通過實戰例程展示了從初始化 LED?相關函數、主循環調用處理函數到解析處理接收到的報文的完整過程。文章詳細介紹了
    的頭像 發表于 07-24 16:18 ?83次閱讀
    第二十九章 <b class='flag-5'>W55MH32</b> Modbus_TCP_<b class='flag-5'>Server</b><b class='flag-5'>示例</b>

    第三十章 W55MH32 HTTP_Server&amp;NetBIOS示例

    本文講解了如何在 W55MH32?芯片上實現 HTTP_Server?與 NetBIOS?功能,并通過 NetBIOS?訪問 HTTP?服務器網頁內容,通過實戰例程展示了在主循環中并行處理 HTTP?與 NetBIOS?相關事務的過程。
    的頭像 發表于 07-24 16:21 ?125次閱讀
    第三十章 <b class='flag-5'>W55MH32</b> HTTP_<b class='flag-5'>Server</b>&amp;NetBIOS<b class='flag-5'>示例</b>