日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

W5500以太网控制器芯片(五):实现FTP客户端

發布時間:2023/12/14 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 W5500以太网控制器芯片(五):实现FTP客户端 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


#W5500以太網控制芯片相關文章鏈接#

上一篇:

W5500以太網控制器芯片(四):實現DNS功能

使用w5500通過以太網口可以實現FTP功能。首先要了解FTP的基本命令和通訊方式。
FTP的本質是TCP連接,所以我們要實現一個TCP客戶端,然后實現一些指定的FTP命令的發送和解析。

FTP基本命令:

命令描述
ABOR中斷數據連接程序
ACCT <account>系統特權帳號
ALLO <bytes>為服務器上的文件存儲器分配字節
APPE <filename>添加文件到服務器同名文件
CDUP <dir path>改變服務器上的父目錄
CWD <dir path>改變服務器上的工作目錄
DELE <filename>刪除服務器上的指定文件
HELP <command>返回指定命令信息
LIST <name>如果是文件名列出文件信息,如果是目錄則列出文件列表
MODE <mode>傳輸模式(S=流模式,B=塊模式,C=壓縮模式)
MKD <directory>在服務器上建立指定目錄
NLST <directory>列出指定目錄內容
NOOP無動作,除了來自服務器上的承認
PASS <password>系統登錄密碼
PASV請求服務器等待數據連接
PORT <address>IP 地址和兩字節的端口 ID
PWD顯示當前工作目錄
QUIT從 FTP 服務器上退出登錄
REIN重新初始化登錄狀態連接
REST <offset>由特定偏移量重啟文件傳遞
RETR <filename>從服務器上找回(復制)文件
RMD <directory>在服務器上刪除指定目錄
RNFR <old path>對舊路徑重命名
RNTO <new path>對新路徑重命名
SITE <params>由服務器提供的站點特殊參數
SMNT <pathname>掛載指定文件結構
STAT <directory>在當前程序或目錄上返回信息
STOR <filename>儲存(復制)文件到服務器上
STOU <filename>儲存文件到服務器名稱上
STRU <type>數據結構(F=文件,R=記錄,P=頁面)
SYST返回服務器使用的操作系統
TYPE <data type>數據類型(A=ASCII,E=EBCDIC,I=binary)
USER <username>系統登錄的用戶名

FTP基本響應碼:

響應代碼解釋說明
110新文件指示器上的重啟標記
120服務器準備就緒的時間(分鐘數)
125打開數據連接,開始傳輸
150打開連接
200成功
202命令沒有執行
211系統狀態回復
212目錄狀態回復
213文件狀態回復
214幫助信息回復
215系統類型回復
220服務就緒
221退出網絡
225打開數據連接
226結束數據連接
227進入被動模式(IP 地址、ID 端口)
230登錄因特網
250文件行為完成
257路徑名建立
331要求密碼
332要求帳號
350文件行為暫停
421服務關閉
425無法打開數據連接
426結束連接
450文件不可用
451遇到本地錯誤
452磁盤空間不足
500無效命令
501錯誤參數
502命令沒有執行
503錯誤指令序列
504無效命令參數
530未登錄網絡
532存儲文件需要帳號
550文件不可用
551不知道的頁類型
552超過存儲分配
553文件名不允許


通過發送和解析這些命令和響應碼,再加上TCP客戶端和服務器,就可以分別實現FTP客戶端和FTP服務器。

下面來實現一個FTP客戶端,下載升級文件:

一般FTP分主動和被動模式,在主動模式下,通常21端口是命令端口,20端口是數據端口。在被動模式下,數據端口不一定。一般客戶端可以先通知服務器,請求被動模式命令端口,然后再解析服務器的回復,得到被動端口,然后去連接,接收數據內容。

1、開始先定義一些參數:

//FTP服務socket通道 #define SOCK_FTP_CTRL 6 #define SOCK_FTP_DATA 7un_l2cval remote_ip; uint16_t remote_port; uint16_t local_port; uint8_t connect_state_control_ftpc = 0; uint8_t connect_state_data_ftpc = 0; uint8_t gModeActivePassiveflag = 0; uint8_t gMenuStart = 0; uint8_t gDataSockReady = 0; uint8_t gDataPutGetStart = 0;//FTP服務器地址 uint8_t FTP_destip[4] = {192, 1, 1, 1}; uint16_t FTP_destport = 0;//FTP數據傳輸緩沖區 uint8_t FTP_data_buf[1500] = {0};struct ftpc ftpc; struct Command Command;//以太網獲取FTP狀態 uint8_t ether_ftp_sta = 0;//FTP文件大小 u32 ftp_file_size = 0;//FTP文件句柄 int ftp_fd_w = 0;void ftp_data_deal(u8 *buf, u16 len);void ftpc_init(void);uint8_t ftpc_run(void);char proc_ftpc(char *buf);int pportc(char *arg);

頭文件定義:

#ifndef __W5500_FTP_H #define __W5500_FTP_H#include "bsp_include.h"#include <stdint.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <limits.h> #include <stdarg.h>#include "w5500_socket.h"#define LINELEN 128#define _MAX_SS 1400/* FTP Responses */ #define R_150 150 /* File status ok; opening data conn */ #define R_200 200 /* 'Generic' command ok */ #define R_220 220 /* Service ready for new user. */ #define R_226 226 /* Closing data connection. File transfer/abort successful */ #define R_227 227 /* Entering passive mode (h1,h2,h3,h4,p1,p2) */ #define R_230 230 /* User logged in, proceed */ #define R_331 331 /* User name okay, need password. */#define TransferAscii 'A' #define TransferBinary 'I'enum ftpc_type {ASCII_TYPE,IMAGE_TYPE, };enum ftpc_datasock_state{DATASOCK_IDLE,DATASOCK_READY,DATASOCK_START };enum ftpc_datasock_mode{PASSIVE_MODE,ACTIVE_MODE }; enum CommandFirst {f_nocmd,f_dir,f_put,f_get, }; enum CommandSecond {s_nocmd,s_dir,s_put,s_get, }; struct Command {enum CommandFirst First;enum CommandSecond Second; }; struct ftpc {uint8_t control; /* Control stream */uint8_t data; /* Data stream */enum ftpc_type type; /* Transfer type */enum ftpc_datasock_state dsock_state;enum ftpc_datasock_mode dsock_mode;char workingdir[LINELEN];char filename[LINELEN]; };typedef union _un_l2cval {uint32_t lVal;uint8_t cVal[4]; }un_l2cval;void Ethernet_FTP_service_deal(void);#endif

2、定義一個FTP服務,下載完成后退出

//初始化FTP Client void ftpc_init(void) {connect_state_control_ftpc = 0;connect_state_data_ftpc = 0;gModeActivePassiveflag = 0;gMenuStart = 0;gDataSockReady = 0;gDataPutGetStart = 0;ftp_file_size = 0;ftp_fd_w = 0;//創建FTP命令socketftpc.dsock_mode = PASSIVE_MODE;local_port = 35000;w5500_socket(SOCK_FTP_CTRL, Sn_MR_TCP, FTP_destport, 0x0); }//以太網FTP服務處理 void Ethernet_FTP_service_deal(void) {//下載初始化if (ether_ftp_sta == 0){ether_ftp_sta = 1;ftpc_init();}//下載完成if (ether_ftp_sta > 2){//關閉socket通道w5500_disconnect(SOCK_FTP_DATA);w5500_close(SOCK_FTP_DATA);w5500_disconnect(SOCK_FTP_CTRL);w5500_close(SOCK_FTP_CTRL);if (ether_ftp_sta == 3) //下載成功{ol_print(DEBUG_CHN, 0, "ETH FTP success\n");System_Sta.FTP_Sta = FTP_SUCCESS;}else if (ether_ftp_sta == 0xFF) //下載失敗{ol_print(DEBUG_CHN, 0, "ETH FTP fail\n");System_Sta.FTP_Sta = FTP_FAIL;}ether_ftp_sta = 0;return;}ftpc_run(); //FTP客戶端狀態機 }

3、實現FTP下載文件的命令發送流程
(1)、連接FTP服務器,提供用戶名密碼。
(2)、通知FTP服務器被動模式,解析被動模式端口(PASV),打開數據通道
(3)、查詢指定的文件在FTP服務器是否存在,獲取文件大小(LIST),數據通道斷開
(4)、再次請求數據通道端口(PASV),打開數據通道
(5)、分段讀取文件(RETR),讀取完成,數據通道斷開
(6)、比較讀取到的文件和之前查詢的長度是否一致

//FTP客戶端狀態機 uint8_t ftpc_run(void) {uint16_t size = 0;long ret = 0;uint32_t recv_byte;uint32_t remain_datasize;uint8_t dat[50] = {0,};//FTP命令通道處理switch (getSn_SR(SOCK_FTP_CTRL)){case SOCK_ESTABLISHED:{//socket連接成功if (!connect_state_control_ftpc){ol_print(DEBUG_CHN, 0, "%d:FTP Connected\r\n", SOCK_FTP_CTRL);strcpy(ftpc.workingdir, "/");connect_state_control_ftpc = 1;}//有命令要執行if (gMenuStart){ol_print(DEBUG_CHN, 0, "FTP cmd start:%d\r\n", ether_ftp_sta);gMenuStart = 0;if (ether_ftp_sta == 1) //開始查詢文件基本信息{if (ftpc.dsock_mode == PASSIVE_MODE) //被動模式下載{sprintf((char *)dat, "PASV\r\n");w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));Command.First = f_dir;}else{wiz_NetInfo gWIZNETINFO;ctlnetwork(CN_GET_NETINFO, (void *)&gWIZNETINFO);sprintf((char *)dat, "PORT %d,%d,%d,%d,%d,%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3], (uint8_t)(local_port >> 8), (uint8_t)(local_port & 0x00ff));w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));Command.First = f_dir;gModeActivePassiveflag = 1;}}else if (ether_ftp_sta == 2) //開始下載文件,需要重新分配一次端口{if (ftpc.dsock_mode == PASSIVE_MODE) //被動模式下載{sprintf((char *)dat, "PASV\r\n");w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));Command.First = f_get;}else{wiz_NetInfo gWIZNETINFO;ctlnetwork(CN_GET_NETINFO, (void *)&gWIZNETINFO);sprintf((char *)dat, "PORT %d,%d,%d,%d,%d,%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3], (uint8_t)(local_port >> 8), (uint8_t)(local_port & 0x00ff));w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));Command.First = f_get;gModeActivePassiveflag = 1;}}}//數據通道就緒,可以開始發送FTP命令if (gDataSockReady){gDataSockReady = 0;switch (Command.First){case f_dir: //列出要下載的FTP文件信息// sprintf(dat, "MLSD\r\n");sprintf((char *)dat, "LIST %s\r\n", System_Para.Filename);w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));break;case f_get:ol_print(DEBUG_CHN, 0, ">get file name?%s\n", System_Para.Filename);sprintf((char *)dat, "RETR %s\r\n", System_Para.Filename);w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));break;}}//接收到FTP命令通道數據if ((size = getSn_RX_RSR(SOCK_FTP_CTRL)) > 0){// Don't need to check SOCKERR_BUSY because it doesn't not occur.memset(FTP_data_buf, 0, _MAX_SS);if (size > _MAX_SS)size = _MAX_SS - 1;ret = w5500_recv(SOCK_FTP_CTRL, FTP_data_buf, size);FTP_data_buf[ret] = '\0';if (ret != size){if (ret == SOCK_BUSY)return 0;if (ret < 0){ol_print(DEBUG_CHN, 0, "%d:recv() error:%ld\r\n", SOCK_FTP_CTRL, ret);w5500_close(SOCK_FTP_CTRL);//命令通道接收異常,關閉FTP下載ether_ftp_sta = 0xFF;return ret;}}ol_print(DEBUG_CHN, 0, "Rcvd Command: %s\r\n", FTP_data_buf);proc_ftpc((char *)FTP_data_buf); //處理命令}break;}case SOCK_CLOSE_WAIT: //SOCKET關閉等待{ol_print(DEBUG_CHN, 0, "%d:CloseWait\r\n", SOCK_FTP_CTRL);if ((ret = w5500_disconnect(SOCK_FTP_CTRL)) != SOCK_OK)return ret;ol_print(DEBUG_CHN, 0, "%d:Closed\r\n", SOCK_FTP_CTRL);break;}case SOCK_CLOSED: //SOCKET關閉狀態{ol_print(DEBUG_CHN, 0, "%d:FTPStart\r\n", SOCK_FTP_CTRL);if ((ret = w5500_socket(SOCK_FTP_CTRL, Sn_MR_TCP, FTP_destport, 0x0)) != SOCK_FTP_CTRL){ol_print(DEBUG_CHN, 0, "%d:socket() error:%ld\r\n", SOCK_FTP_CTRL, ret);w5500_close(SOCK_FTP_CTRL);return ret;}break;}case SOCK_INIT: //SOCKET初始化狀態{ol_print(DEBUG_CHN, 0, "%d:Opened\r\n", SOCK_FTP_CTRL);if ((ret = w5500_connect(SOCK_FTP_CTRL, FTP_destip, FTP_destport)) != SOCK_OK){ol_print(DEBUG_CHN, 0, "%d:Connect error\r\n", SOCK_FTP_CTRL);return ret;}connect_state_control_ftpc = 0;ol_print(DEBUG_CHN, 0, "%d:Connectting...\r\n", SOCK_FTP_CTRL);break;}}//FTP數據通道switch (getSn_SR(SOCK_FTP_DATA)){case SOCK_ESTABLISHED:{if (!connect_state_data_ftpc){ol_print(DEBUG_CHN, 0, "%d:FTP Data socket Connected\r\n", SOCK_FTP_DATA);connect_state_data_ftpc = 1;}//開始接收數據if (gDataPutGetStart){ol_print(DEBUG_CHN, 0, "%d:rec ftp data:%d\r\n", SOCK_FTP_DATA, Command.Second);switch (Command.Second){case s_dir: //查詢文件信息是小文本,發送完后數據通道會直接斷開,此段程序一般無法進入{while (1){if ((remain_datasize = getSn_RX_RSR(SOCK_FTP_DATA)) > 0){while (1){memset(FTP_data_buf, 0, _MAX_SS);if (remain_datasize > _MAX_SS)recv_byte = _MAX_SS;elserecv_byte = remain_datasize;ret = w5500_recv(SOCK_FTP_DATA, FTP_data_buf, recv_byte);if (ret > 0){ftp_data_deal(FTP_data_buf, ret);}else{//傳輸失敗,結束FTP下載ether_ftp_sta = 0xFF;return 0;}remain_datasize -= ret;if (remain_datasize <= 0)break;}}else{if (getSn_SR(SOCK_FTP_DATA) != SOCK_ESTABLISHED)break;}}gDataPutGetStart = 0;Command.Second = s_nocmd;break;}case s_get:{while (1){if ((remain_datasize = getSn_RX_RSR(SOCK_FTP_DATA)) > 0){while (1){memset(FTP_data_buf, 0, _MAX_SS);if (remain_datasize > _MAX_SS)recv_byte = _MAX_SS;elserecv_byte = remain_datasize;ret = w5500_recv(SOCK_FTP_DATA, FTP_data_buf, recv_byte);if (ret > 0){ftp_data_deal(FTP_data_buf, ret);}else{//傳輸失敗,結束FTP下載ether_ftp_sta = 0xFF;return 0;}remain_datasize -= ret;if (remain_datasize <= 0)break;}}else{if (getSn_SR(SOCK_FTP_DATA) != SOCK_ESTABLISHED)break;}}gDataPutGetStart = 0;Command.Second = s_nocmd;break;}}}break;}case SOCK_CLOSE_WAIT:{//對于較小的數據,一次傳輸后FTP數據通道會直接關閉,所以在SOCK_CLOSE_WAIT狀態下也要先接收一次數據if (gDataPutGetStart){ol_print(DEBUG_CHN, 0, "%d:rec ftp data wait:%d\r\n", SOCK_FTP_DATA, Command.Second);switch (Command.Second){case s_dir:{while (1){if ((remain_datasize = getSn_RX_RSR(SOCK_FTP_DATA)) > 0){while (1){memset(FTP_data_buf, 0, _MAX_SS);if (remain_datasize > _MAX_SS)recv_byte = _MAX_SS;elserecv_byte = remain_datasize;ret = w5500_recv(SOCK_FTP_DATA, FTP_data_buf, recv_byte);if (ret > 0){ftp_data_deal(FTP_data_buf, ret);}else{//傳輸失敗,結束FTP下載ether_ftp_sta = 0xFF;return 0;}remain_datasize -= ret;if (remain_datasize <= 0)break;}}else{if (getSn_SR(SOCK_FTP_DATA) != SOCK_ESTABLISHED)break;}}gDataPutGetStart = 0;Command.Second = s_nocmd;break;}case s_get:{while (1){if ((remain_datasize = getSn_RX_RSR(SOCK_FTP_DATA)) > 0){while (1){memset(FTP_data_buf, 0, _MAX_SS);if (remain_datasize > _MAX_SS)recv_byte = _MAX_SS;elserecv_byte = remain_datasize;ret = w5500_recv(SOCK_FTP_DATA, FTP_data_buf, recv_byte);if (ret > 0){ftp_data_deal(FTP_data_buf, ret);}else{//傳輸失敗,結束FTP下載ether_ftp_sta = 0xFF;return 0;}remain_datasize -= ret;if (remain_datasize <= 0)break;}}else{if (getSn_SR(SOCK_FTP_DATA) != SOCK_ESTABLISHED)break;}}gDataPutGetStart = 0;Command.Second = s_nocmd;break;}}}ol_print(DEBUG_CHN, 0, "%d:CloseWait\r\n", SOCK_FTP_DATA);if ((ret = w5500_disconnect(SOCK_FTP_DATA)) != SOCK_OK){//無法正常關閉數據通道,FTP失敗ether_ftp_sta = 0xFF;return 0;}else{//關閉數據通道成功,數據解析完畢,進入FTP下一步if (ether_ftp_sta == 1) //文件信息讀取結束{ether_ftp_sta = 2;gMenuStart = 1;}else if (ether_ftp_sta == 2) //文件下載結束,準備升級{ether_ftp_sta = 3;vfs_close(ftp_fd_w);//讀取文件大小ret = vfs_file_size("/fota/ftptext.pack");ol_print(DEBUG_CHN, 0, "FTP file size:%d,%d\n", ftp_file_size, ret);if (ftp_file_size != System_Para.Filesize){ether_ftp_sta = 0xFF;}ret = vfs_rename("/fota/ftptext.pack", "/fota/fota.pack");if (ret != 0){ether_ftp_sta = 0xFF;}}}ol_print(DEBUG_CHN, 0, "%d:Closed\r\n", SOCK_FTP_DATA);break;}case SOCK_CLOSED:{if (ftpc.dsock_state == DATASOCK_READY){if (ftpc.dsock_mode == PASSIVE_MODE){ol_print(DEBUG_CHN, 0, "%d:FTPDataStart, port : %d\r\n", SOCK_FTP_DATA, local_port);if ((ret = w5500_socket(SOCK_FTP_DATA, Sn_MR_TCP, local_port, 0x0)) != SOCK_FTP_DATA){ol_print(DEBUG_CHN, 0, "%d:socket() error:%ld\r\n", SOCK_FTP_DATA, ret);w5500_close(SOCK_FTP_DATA);return ret;}local_port++;if (local_port > 50000)local_port = 35000;}else{ol_print(DEBUG_CHN, 0, "%d:FTPDataStart, port : %d\r\n", SOCK_FTP_DATA, local_port);if ((ret = w5500_socket(SOCK_FTP_DATA, Sn_MR_TCP, local_port, 0x0)) != SOCK_FTP_DATA){ol_print(DEBUG_CHN, 0, "%d:socket() error:%ld\r\n", SOCK_FTP_DATA, ret);w5500_close(SOCK_FTP_DATA);return ret;}local_port++;if (local_port > 50000)local_port = 35000;}ftpc.dsock_state = DATASOCK_START;}break;}case SOCK_INIT:{ol_print(DEBUG_CHN, 0, "%d:Opened\r\n", SOCK_FTP_DATA);if (ftpc.dsock_mode == ACTIVE_MODE){if ((ret = w5500_listen(SOCK_FTP_DATA)) != SOCK_OK){OSI_LOGI(0, "w5500 FTP Listen error %d", SOCK_FTP_DATA);return ret;}gDataSockReady = 1;OSI_LOGI(0, "w5500 FTP Listen ok:%d", SOCK_FTP_DATA);}else{if ((ret = w5500_connect(SOCK_FTP_DATA, remote_ip.cVal, remote_port)) != SOCK_OK){ol_print(DEBUG_CHN, 0, "%d:Connect error\r\n", SOCK_FTP_DATA);return ret;}gDataSockReady = 1; //FTP數據通道開啟完成,準備執行命令}connect_state_data_ftpc = 0;break;}}return 0; }

解析FTP相應碼:

//FTP服務器回復的協議解析 char proc_ftpc(char *buf) {uint16_t Responses;uint8_t dat[30] = {0,};Responses = (buf[0] - '0') * 100 + (buf[1] - '0') * 10 + (buf[2] - '0');switch (Responses){case R_220: /* Service ready for new user. */ol_print(DEBUG_CHN, 0, "USER %s\n", System_Para.User);sprintf((char *)dat, "USER %s\r\n", System_Para.User);ol_print(DEBUG_CHN, 0, "\r\n");w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));break;case R_331: /* User name okay, need password. */ol_print(DEBUG_CHN, 0, "PASS %s\n", System_Para.Pass);sprintf((char *)dat, "PASS %s\r\n", System_Para.Pass);w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));break;case R_230: //登錄成功,通知FTP服務器使用ASCII通訊ol_print(DEBUG_CHN, 0, "\r\nlogged in, proceed\r\n");sprintf((char *)dat, "TYPE %c\r\n", TransferAscii);ftpc.type = ASCII_TYPE;w5500_send(SOCK_FTP_CTRL, (uint8_t *)dat, strlen((char *)dat));break;case R_200: //設置ASCII模式完成,服務器回復成功{if ((ftpc.dsock_mode == ACTIVE_MODE) && gModeActivePassiveflag){ftpc.dsock_state = DATASOCK_READY;gModeActivePassiveflag = 0;}else{gMenuStart = 1;}break;}case R_150: //命令發送成功,開始傳輸數據{switch (Command.First){case f_dir:Command.First = f_nocmd;Command.Second = s_dir;gDataPutGetStart = 1;break;case f_get:Command.First = f_nocmd;Command.Second = s_get;gDataPutGetStart = 1;break;}break;}case R_226: //數據通道結束連接gMenuStart = 1;break;case R_227: //被動模式設置成功,服務器返回被動模式數據端口{if (pportc(buf) == -1){ol_print(DEBUG_CHN, 0, "Bad port syntax\r\n");//轉換被動模式失敗,結束FTPether_ftp_sta = 0xFF;}else{ol_print(DEBUG_CHN, 0, "Go Open Data Sock...\r\n ");ftpc.dsock_mode = PASSIVE_MODE;ftpc.dsock_state = DATASOCK_READY; //開啟FTP數據通道}break;}default:OSI_LOGI(0, "w5500 FTP Default Status:%d", (uint16_t)Responses);gDataSockReady = 1;break;}return 1; }

計算被動模式端口:

//計算被動模式連接端口 int pportc(char *arg) {int i;char *tok = 0;strtok(arg, "(");for (i = 0; i < 4; i++){if (i == 0)tok = strtok(NULL, ",\r\n");elsetok = strtok(NULL, ",");remote_ip.cVal[i] = (uint8_t)atoi(tok);if (!tok){ol_print(DEBUG_CHN, 0, "bad pport : %s\r\n", arg);return -1;}}remote_port = 0;for (i = 0; i < 2; i++){tok = strtok(NULL, ",\r\n");remote_port <<= 8;remote_port += atoi(tok);if (!tok){ol_print(DEBUG_CHN, 0, "bad pport : %s\r\n", arg);return -1;}}ol_print(DEBUG_CHN, 0, "ip : %d.%d.%d.%d, port : %d\r\n", remote_ip.cVal[0], remote_ip.cVal[1], remote_ip.cVal[2], remote_ip.cVal[3], remote_port);return 0; }

5、處理FTP接收數據
僅供參考,文件參數信息解析的是filezilla服務器的默認信息。文件原始數據的接收也要根據w5500設備所在的文件存儲類型(文件系統或者是無系統的FLASH)自行處理。

//查找下一空格后的第一個字符 s32 search_space(char *buf, u16 max_len) {char *p = buf;u8 falg = 0, res = 0;while (falg < 2){if (*p == 0x20){falg = 1;}else{if (falg == 1){falg = 2;break;}}res++;if (res > max_len){return 0xff;}p++;}return res; }//接收處理FTP文件、命令協議 void ftp_data_deal(u8 *buf, u16 len) {u8 pos = 0;u32 file_size = 0;s32 ret;//-r--r--r-- 1 ftp ftp 89344 May 20 2021 FTP.bin//查詢文件信息解析文件大小if (Command.Second == s_dir){ol_print(DEBUG_CHN, 0, "FTP file info,%d:%s", len, buf);//解析過第一個空格 文件權限pos = search_space((char *)buf, len);if (pos == 0xFF)return;buf += pos;//解析第二個空格 文件硬連接數len = len - pos;pos = search_space((char *)buf, len);if (pos == 0xFF)return;buf += pos;//解析第三個空格 文件所有人len = len - pos;pos = search_space((char *)buf, len);if (pos == 0xFF)return;buf += pos;//解析第四個空格 文件所有組len = len - pos;pos = search_space((char *)buf, len);if (pos == 0xFF)return;buf += pos;//解析文件大小file_size = Str2Num((char *)buf, &pos);ol_print(DEBUG_CHN, 0, "FTP file size:%d\r\n", file_size);System_Para.Filesize = file_size;}else if (Command.Second == s_get) //下載文件{OSI_LOGI(0, "w5500 FTP page size:%d", len);//創建文件if (ftp_file_size == 0){//打開文件vfs_mkdir("/fota", 0);ftp_fd_w = vfs_open("/fota/ftptext.pack", O_CREAT | O_RDWR | O_TRUNC);if (ftp_fd_w < 0){ol_print(DEBUG_CHN, 0, "FTP file open fail\r\n");vfs_close(ftp_fd_w);ether_ftp_sta = 0xFF;return;}}//傳輸文件ret = vfs_write(ftp_fd_w, buf, len);if (ret <= 0){ol_print(DEBUG_CHN, 0, "FTP file write fail,%d\r\n", ftp_file_size);vfs_close(ftp_fd_w);ether_ftp_sta = 0xFF;return;}else if (ret < len) //一次未傳輸完成{pos = len - ret;ret = vfs_write(ftp_fd_w, buf, pos);if (ret != pos){ol_print(DEBUG_CHN, 0, "FTP file write fail,%d\r\n", ftp_file_size);vfs_close(ftp_fd_w);ether_ftp_sta = 0xFF;return;}}else{ftp_file_size += len;}OSI_LOGI(0, "w5500 FTP total size:%d", ftp_file_size);} }

總結

以上是生活随笔為你收集整理的W5500以太网控制器芯片(五):实现FTP客户端的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。