0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于UDP的簡(jiǎn)單文件傳輸協(xié)議TFTP設(shè)計(jì)

CHANBAEK ? 來(lái)源:木南創(chuàng)智 ? 作者:尹家軍 ? 2022-12-14 15:06 ? 次閱讀

前面我們已經(jīng)實(shí)現(xiàn)了UDP的回環(huán)客戶端和回環(huán)服務(wù)器的簡(jiǎn)單應(yīng)用,接下來(lái)我們實(shí)現(xiàn)一個(gè)基于UDP的簡(jiǎn)單文件傳輸協(xié)議TFTP。

1 、 TFTP****協(xié)議簡(jiǎn)介

TFTP是TCP/IP協(xié)議族中的一個(gè)用來(lái)在客戶機(jī)與服務(wù)器之間進(jìn)行簡(jiǎn)單文件傳輸?shù)膮f(xié)議,提供不復(fù)雜、開(kāi)銷(xiāo)不大的文件傳輸服務(wù)。端口號(hào)為69

TFTP是一種簡(jiǎn)單的文件傳輸協(xié)議。目標(biāo)是在UDP之上上建立一個(gè)類(lèi)似于FTP的但僅支持文件上傳和下載功能的傳輸協(xié)議,所以它不包含F(xiàn)TP協(xié)議中的目錄操作和用戶權(quán)限等內(nèi)容。

TFTP報(bào)文的頭兩個(gè)字節(jié)表示操作碼,共有5中操作碼,如下表:

讀請(qǐng)求和寫(xiě)請(qǐng)求功能碼的數(shù)據(jù)報(bào)文格式是一樣的,所以TFTP報(bào)文又可表述為4種形式。對(duì)于讀請(qǐng)求或者寫(xiě)請(qǐng)求,文件名字段說(shuō)明客戶要讀或?qū)懙奈挥诜?wù)器的上的文件并以0字節(jié)作為結(jié)束,模式字段是一個(gè)ASCII碼串,同樣以0字節(jié)結(jié)束。讀請(qǐng)求和寫(xiě)請(qǐng)求的報(bào)文格式:

其次是數(shù)據(jù)包,起包括2個(gè)字節(jié)的塊編號(hào)以及0-512個(gè)字節(jié)的數(shù)據(jù)信息。數(shù)據(jù)包相對(duì)比較簡(jiǎn)單,其報(bào)文格式:

再者為確認(rèn)包。確認(rèn)包也有2個(gè)字節(jié)的塊編號(hào)。其數(shù)據(jù)格式:

最后一種TFTP報(bào)文類(lèi)型是差錯(cuò)報(bào)文,它的操作碼為5.它用于服務(wù)器不能處理讀請(qǐng)求或者寫(xiě)請(qǐng)求的情況。在文件傳輸?shù)倪^(guò)程中的讀和寫(xiě)也會(huì)導(dǎo)致傳送這種報(bào)文,接著停止傳輸。錯(cuò)誤包的報(bào)文格式:

TFTP的工作過(guò)程很像停止等待協(xié)議,發(fā)送完一個(gè)文件塊后就等待對(duì)方的確認(rèn),確認(rèn)時(shí)應(yīng)指明所確認(rèn)的塊號(hào)。發(fā)送完數(shù)據(jù)后在規(guī)定時(shí)間內(nèi)收不到確認(rèn)就要重發(fā)數(shù)據(jù)PDU,發(fā)送確認(rèn)PDU的一方若在規(guī)定時(shí)間內(nèi)收不到下一個(gè)文件塊,也要重發(fā)確認(rèn)PDU。這樣保證文件的傳送不致因某一個(gè)數(shù)據(jù)報(bào)的丟失而告失敗。

2 、 TFTP****協(xié)議棧設(shè)計(jì)

前面我們簡(jiǎn)單的介紹了TFTP協(xié)議,接下來(lái)我們看看該如何實(shí)現(xiàn)其編程。它有5種操作碼,我們要做的就是實(shí)現(xiàn)對(duì)這5種操作碼的響應(yīng)。

2.1 、讀請(qǐng)求實(shí)現(xiàn)

所謂讀請(qǐng)求,就是客戶端請(qǐng)求從服務(wù)器獲取文件,那么服務(wù)器需要做的自然是響應(yīng)客戶端的請(qǐng)求。但我們并沒(méi)有文件,所以不管它請(qǐng)求什么文件,我們均給它返回內(nèi)容和大小相同的測(cè)試文件。

1 /* TFTP讀請(qǐng)求處理*/
 2 int TftpReadProcess(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, char* FileName)
 3 {
 4   tftp_connection_args *args = NULL;
 5  
 6   /* 這個(gè)函數(shù)在回調(diào)函數(shù)中被調(diào)用,因此中斷被禁用,因此我們可以使用常規(guī)的malloc */
 7   args = mem_malloc(sizeof(tftp_connection_args));
 8  
 9   if (!args)
10   {
11     /* 內(nèi)存分配失敗 */
12     SendTftpErrorMessage(upcb, to, to_port, TFTP_ERR_NOTDEFINED);
13  
14     CleanTftpConnection(upcb, args);
15  
16     return 0;
17   }
18  
19   /* i初始化連接結(jié)構(gòu)體  */
20   args->op = TFTP_RRQ;
21   args->remote_port = to_port;
22   args->block = 1; /* 塊號(hào)從1開(kāi)始 */
23   args->tot_bytes = 10*1024*1024;
24  
25   /* 注冊(cè)回調(diào)函數(shù) */
26   udp_recv(upcb, RrqReceiveCallback, args);
27  
28   /* 通過(guò)發(fā)送第一個(gè)塊來(lái)建立連接,后續(xù)塊在收到ACK后發(fā)送*/
29    SendNextBlock(upcb, args, to, to_port);
30  
31   return 1;
32 }

2.2 、寫(xiě)請(qǐng)求實(shí)現(xiàn)

寫(xiě)請(qǐng)求就是客戶端希望向服務(wù)器傳送文件,在這里我們只是實(shí)現(xiàn)TFTP服務(wù)器的功能,沒(méi)必要將收到的文件真正保存到一個(gè)地方,所以只是做接收文件的過(guò)程并不將其寫(xiě)到存儲(chǔ)器,簡(jiǎn)單的說(shuō)就是只在內(nèi)存中而不會(huì)寫(xiě)入Flash等。

1 /* TFTP寫(xiě)請(qǐng)求處理 */
 2 int TftpWriteProcess(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, char *FileName)
 3 {
 4   tftp_connection_args *args = NULL;
 5  
 6   /* 這個(gè)函數(shù)在回調(diào)函數(shù)中被調(diào)用,因此中斷被禁用,因此我們可以使用常規(guī)的malloc */
 7   args = mem_malloc(sizeof(tftp_connection_args));
 8  
 9   if (!args)
10   {
11     SendTftpErrorMessage(upcb, to, to_port, TFTP_ERR_NOTDEFINED);
12  
13     CleanTftpConnection(upcb, args);
14  
15     return 0;
16   }
17  
18   args->op = TFTP_WRQ;
19   args->remote_port = to_port;
20   args->block = 0;      //WRQ響應(yīng)的塊號(hào)為0
21   args->tot_bytes = 0;
22  
23   /* 為控制塊注冊(cè)回調(diào)函數(shù) */
24   udp_recv(upcb, WrqReceiveCallback, args);
25  
26   /* 通過(guò)發(fā)送第一個(gè)ack來(lái)發(fā)起寫(xiě)事務(wù) */
27   SendTftpAckPacket(upcb, to, to_port, args->block);
28  
29   return 0;
30 }

2.3 、數(shù)據(jù)包操作

無(wú)論是讀請(qǐng)求還是寫(xiě)請(qǐng)求,最終的目的無(wú)非是要傳送數(shù)據(jù),所以數(shù)據(jù)包自然也是我們需要構(gòu)造和傳送的。其對(duì)應(yīng)的就是數(shù)據(jù)包操作碼,我們?cè)O(shè)計(jì)程序如下:

1 /* 構(gòu)造并且傳送數(shù)據(jù)包 */
 2 static int SendTftpDataPacket(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, int block,char *buf, int buflen)
 3 {
 4   /* 將開(kāi)始的2個(gè)字節(jié)設(shè)置為功能碼 */
 5   SetTftpOpCode(buf, TFTP_DATA);
 6  
 7   /* 將后續(xù)2個(gè)字節(jié)設(shè)置為塊號(hào) */
 8   SetTftpBlockNumber(buf, block);
 9  
10   /* 在后續(xù)設(shè)置n個(gè)字節(jié)的數(shù)據(jù) */
11  
12   /* 發(fā)送數(shù)據(jù)包 */
13   return SendTftpMessage(upcb, to, to_port, buf, buflen + 4);
14 }

2.4 、確認(rèn)包操作

在傳送數(shù)據(jù)包后,收到?jīng)]收到,發(fā)送方是不知道的,怎么辦呢?這時(shí)候接受方接收到后,會(huì)給出一個(gè)確認(rèn)包。其對(duì)應(yīng)的就是確認(rèn)操作碼,那么我們還需實(shí)現(xiàn)確認(rèn)包的構(gòu)造和發(fā)送。

1 /*構(gòu)造并發(fā)送確認(rèn)包*/
 2 int SendTftpAckPacket(struct udp_pcb *upcb,const ip_addr_t *to, int to_port, int block)
 3 {
 4   /* 創(chuàng)建一個(gè)TFTP ACK包 */
 5   char packet[TFTP_ACK_PKT_LEN];
 6  
 7   /* 將開(kāi)始的2個(gè)字節(jié)設(shè)置為功能碼 */
 8   SetTftpOpCode(packet, TFTP_ACK);
 9  
10   /* 制定ACK的塊號(hào) */
11   SetTftpBlockNumber(packet, block);
12  
13   return SendTftpMessage(upcb, to, to_port, packet, TFTP_ACK_PKT_LEN);
14 }

2.5 、錯(cuò)誤包操作

在包傳送的過(guò)程中,有沒(méi)有可能出現(xiàn)錯(cuò)誤呢?當(dāng)然是有的,這就需要所謂的錯(cuò)誤包操作碼。在服務(wù)器不能處理讀請(qǐng)求或者寫(xiě)請(qǐng)求的情況下。在文件傳輸?shù)倪^(guò)程中的讀和寫(xiě)也會(huì)導(dǎo)致傳送這種報(bào)文,接著停止傳輸。我們也需要開(kāi)發(fā)構(gòu)造和傳送錯(cuò)誤包的函數(shù)。

1 /* 構(gòu)造并向客戶端發(fā)送一條錯(cuò)誤消息 */
 2 static int SendTftpErrorMessage(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, tftp_errorcode err)
 3 {
 4   char buf[512];
 5   int error_len;
 6  
 7   error_len = ConstructTftpErrorMessage(buf, err);
 8  
 9   return SendTftpMessage(upcb, to, to_port, buf, error_len);
10 }

3 、 TFTP****服務(wù)器實(shí)現(xiàn)

我們已經(jīng)實(shí)現(xiàn)了UDP服務(wù)器,而且也實(shí)現(xiàn)了簡(jiǎn)單的TFTP協(xié)議棧,接下來(lái)的工作就是在UDP基礎(chǔ)上實(shí)現(xiàn)TFTP服務(wù)器功能。前面我們已經(jīng)提到過(guò),復(fù)雜的服務(wù)器應(yīng)用只是回到函數(shù)的功能不一樣,所以開(kāi)發(fā)的過(guò)程并無(wú)區(qū)別。

首先我們來(lái)實(shí)現(xiàn)初始化部分。創(chuàng)建新的UDP控制塊。綁定到制定的服務(wù)器端口,我們要實(shí)現(xiàn)TFTP服務(wù)器,而TFTP協(xié)議的端口號(hào)為69,所以我們將其綁定到該端口。最后注冊(cè)TFTP服務(wù)器的回調(diào)函數(shù)。

1 /* 初始化TFTP服務(wù)器 */
 2 void Tftp_Server_Initialization(void)
 3 {
 4   err_t err;
 5   struct udp_pcb *tftp_server_pcb = NULL;
 6  
 7   /* 生成新的 UDP PCB控制塊 */
 8   tftp_server_pcb = udp_new();
 9  
10   /* 判斷UDP控制塊是否正確生成 */
11   if (NULL == tftp_server_pcb)
12   { 
13     return;
14   }
15  
16   /* 綁定PCB控制塊到指定端口 */
17   err = udp_bind(tftp_server_pcb, IP_ADDR_ANY, UDP_TFTP_SERVER_PORT);
18  
19   if (err != ERR_OK)
20   {
21     udp_remove(tftp_server_pcb);
22     return;
23   }
24  
25   /* 注冊(cè)TFTP服務(wù)器處理函數(shù) */
26   udp_recv(tftp_server_pcb, TftpServerCallback, NULL);
27 }

在初始化中注冊(cè)了回調(diào)函數(shù),所以我們還要實(shí)現(xiàn)TFTP服務(wù)器的回調(diào)函數(shù)。這部分出于結(jié)構(gòu)清晰的考慮,我們分成兩個(gè)函數(shù)來(lái)寫(xiě)。

1 /* TFTP服務(wù)器回調(diào)函數(shù) */
 2 static void TftpServerCallback(void *arg, struct udp_pcb *upcb, struct pbuf *p,const ip_addr_t *addr, u16_t port)
 3 {
 4   /* 處理新的連接請(qǐng)求 */
 5   ProcessTftpRequest(p, addr, port);
 6  
 7   pbuf_free(p);
 8 }
 9 /* 從每一個(gè)來(lái)自addr:port的新請(qǐng)求創(chuàng)建一個(gè)新的端口來(lái)服務(wù)響應(yīng),并啟動(dòng)響應(yīng)過(guò)程 */
10 static void ProcessTftpRequest(struct pbuf *pkt_buf, const ip_addr_t *addr, u16_t port)
11 {
12   tftp_opcode op = ExtractTftpOpcode(pkt_buf->payload);
13   char FileName[50] = {0};
14   struct udp_pcb *upcb = NULL;
15   err_t err;
16  
17   /* 生成新的UDP PCB控制塊 */
18   upcb = udp_new();
19   if (!upcb)
20   {
21     return;
22   }
23  
24   /* 連接 */
25   err = udp_connect(upcb, addr, port);
26   if (err != ERR_OK)
27   { 
28     return;
29   }
30  
31   ExtractTftpFilename(FileName, pkt_buf->payload);
32  
33   switch (op)
34   {
35   case TFTP_RRQ:
36     {
37  
38       TftpReadProcess(upcb, addr, port, FileName);
39       break;
40     }
41   case TFTP_WRQ:
42     {
43       /* 啟動(dòng)TFTP寫(xiě)模式 */
44       TftpWriteProcess(upcb, addr, port, FileName);
45       break;
46     }
47   default:
48     {
49       /* 異常,發(fā)送錯(cuò)誤消息 */
50       SendTftpErrorMessage(upcb, addr, port, TFTP_ERR_ACCESS_VIOLATION);
51  
52       udp_remove(upcb);
53  
54       break;
55     }
56   }
57 }

在回調(diào)函數(shù)中,我們實(shí)現(xiàn)了對(duì)TFTP讀請(qǐng)求和寫(xiě)請(qǐng)求的響應(yīng),但這足以驗(yàn)證我們想要實(shí)現(xiàn)的TFTP服務(wù)器的功能。

4 、結(jié)論

本篇我們基于LwIP的UDP實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的FTP服務(wù)器。這個(gè)FTP服務(wù)器只是實(shí)現(xiàn)FTP協(xié)議的功能,具體的應(yīng)用可根據(jù)需要添加。我們使用了TFTP客戶端工具對(duì)這一服務(wù)器進(jìn)行了基本測(cè)試,最終結(jié)果符合我們的預(yù)期。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    9160

    瀏覽量

    85415
  • TFTP
    +關(guān)注

    關(guān)注

    0

    文章

    20

    瀏覽量

    14341
  • UDP
    UDP
    +關(guān)注

    關(guān)注

    0

    文章

    325

    瀏覽量

    33937
  • 文件傳輸協(xié)議
    +關(guān)注

    關(guān)注

    0

    文章

    3

    瀏覽量

    913
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    STM32物聯(lián)網(wǎng)之TFTP文件傳輸

    TFTP協(xié)議理解從以上兩張圖片,我們了解到什么有用信息呢?每一次文件傳輸,首先需要發(fā)起一個(gè)請(qǐng)求,根據(jù)請(qǐng)求幀的操作碼判斷是讀文件還是寫(xiě)文件。
    發(fā)表于 12-30 15:44

    嵌入式開(kāi)發(fā)板iTOP-4412實(shí)現(xiàn)TFTP文件傳輸

    文件傳輸協(xié)議) ,是一個(gè)基于 UDP 協(xié)議實(shí)現(xiàn)的用于在客戶機(jī)和服務(wù)器之間進(jìn)行簡(jiǎn)單文件傳輸
    發(fā)表于 03-15 15:41

    第38章 TFTP簡(jiǎn)單文件傳輸基礎(chǔ)知識(shí)

    轉(zhuǎn)帖本章節(jié)為大家講解TFTP(TrivialFile Transfer Protocol,簡(jiǎn)單文件傳輸協(xié)議)的基礎(chǔ)知識(shí),方便后面章節(jié)的實(shí)戰(zhàn)操作。(本章的知識(shí)點(diǎn)主要整理自網(wǎng)絡(luò))38.1
    發(fā)表于 12-22 08:57

    TFTP協(xié)議

    Protocol,簡(jiǎn)單文件傳輸協(xié)議)是TCP/IP協(xié)議族中的一個(gè)用來(lái)在客戶端與服務(wù)器之間進(jìn)行簡(jiǎn)單文件傳
    發(fā)表于 11-05 09:14

    基于TFTP文件傳輸協(xié)議實(shí)現(xiàn)STM32F407局域網(wǎng)內(nèi)遠(yuǎn)程網(wǎng)絡(luò)升級(jí)

    版本。在學(xué)習(xí)本技術(shù)前,應(yīng)以熟悉TCP/IP中UDP協(xié)議,面向無(wú)連接,可支持同時(shí)多設(shè)備在線同時(shí)TFTP遠(yuǎn)程升級(jí)。BootLoader_TFTP程序下載:APP應(yīng)用程序:Tftpd64工具
    發(fā)表于 01-12 06:29

    tftp文件傳輸出現(xiàn)遠(yuǎn)程主機(jī)強(qiáng)制關(guān)閉了是怎么回事?

    用的是開(kāi)發(fā)板通過(guò)網(wǎng)線連著電腦做調(diào)試。兩個(gè)設(shè)備間的相互ping都是沒(méi)有問(wèn)題。包括TCP和UDP的各種模式都測(cè)過(guò),沒(méi)有問(wèn)題。開(kāi)發(fā)板的文件系統(tǒng)都已經(jīng)有了,但是在調(diào)tftp文件傳輸的時(shí)候,發(fā)現(xiàn)
    發(fā)表于 02-23 15:14

    TFTP服務(wù)器是什么如何下載文件

    服務(wù),復(fù)雜度和開(kāi)銷(xiāo)都很小。 Tftp是什么 tftp是一個(gè)傳輸文件簡(jiǎn)單協(xié)議,它基于
    發(fā)表于 12-12 16:06

    TFTP簡(jiǎn)單文件傳送協(xié)議

    TFTP簡(jiǎn)單文件傳送協(xié)議:T F T P ( Trivial File Transfer Protocol)即簡(jiǎn)單
    發(fā)表于 09-20 17:59 ?15次下載

    什么是TFTP

    什么是TFTP  英文原義:Trivial File Transfer Protocol 中文釋義:簡(jiǎn)單文件傳輸協(xié)議或零碎文件傳輸
    發(fā)表于 02-23 11:25 ?2035次閱讀

    TFTP協(xié)議

    TFTP 是一個(gè)傳輸文件簡(jiǎn)單協(xié)議,它其于UDP 協(xié)議
    發(fā)表于 03-02 16:03 ?34次下載

    TCP協(xié)議UDP協(xié)議的區(qū)別和相同點(diǎn)有哪些 一文看懂TCP協(xié)議UDP協(xié)議的優(yōu)缺點(diǎn)

    。里面包括很多協(xié)議的。UDP只是其中的一個(gè)。之所以命名為T(mén)CP/IP協(xié)議,因?yàn)門(mén)CP,IP協(xié)議是兩個(gè)很重要的協(xié)議,就用他兩命名了。 TCP/
    的頭像 發(fā)表于 05-26 14:35 ?9830次閱讀
    TCP<b class='flag-5'>協(xié)議</b>與<b class='flag-5'>UDP</b><b class='flag-5'>協(xié)議</b>的區(qū)別和相同點(diǎn)有哪些 一文看懂TCP<b class='flag-5'>協(xié)議</b>與<b class='flag-5'>UDP</b><b class='flag-5'>協(xié)議</b>的優(yōu)缺點(diǎn)

    Linux下部署TFTP服務(wù)

    TFTP是 Trivial File Transfer Protocol 的縮寫(xiě),即簡(jiǎn)單文件傳輸協(xié)議,是一個(gè)基于 UDP
    的頭像 發(fā)表于 04-17 14:56 ?1147次閱讀
    Linux下部署<b class='flag-5'>TFTP</b>服務(wù)

    rtthread中使用lwip自帶的tftp功能傳輸文件

    TFTP簡(jiǎn)單文件傳輸協(xié)議)是TCP/IP協(xié)議族中的一個(gè)用來(lái)在客戶機(jī)與服務(wù)器之間進(jìn)行文件傳輸
    發(fā)表于 07-22 14:06 ?1245次閱讀
    rtthread中使用lwip自帶的<b class='flag-5'>tftp</b>功能<b class='flag-5'>傳輸</b><b class='flag-5'>文件</b>

    RT-Thread中使用lwip自帶的tftp功能傳輸文件

    TFTP協(xié)議 TFTP簡(jiǎn)單文件傳輸協(xié)議)是TCP/IP協(xié)議
    的頭像 發(fā)表于 07-24 19:35 ?1598次閱讀
    RT-Thread中使用lwip自帶的<b class='flag-5'>tftp</b>功能<b class='flag-5'>傳輸</b><b class='flag-5'>文件</b>

    FTP、SFTP、TFTP文件傳輸協(xié)議之間的主要區(qū)別

    FTP(File Transfer Protocol,文件傳輸協(xié)議)是用于在計(jì)算機(jī)網(wǎng)絡(luò)中傳輸文件的標(biāo)準(zhǔn)協(xié)議
    的頭像 發(fā)表于 11-15 09:04 ?7011次閱讀
    FTP、SFTP、<b class='flag-5'>TFTP</b><b class='flag-5'>文件傳輸</b><b class='flag-5'>協(xié)議</b>之間的主要區(qū)別