前一節(jié)我們實(shí)現(xiàn)了基于RAW API的UDP服務(wù)器,在接下來(lái),我們進(jìn)一步利用RAW API實(shí)現(xiàn)UDP客戶端。
1 、 UDP****協(xié)議簡(jiǎn)述
UDP協(xié)議全稱是用戶數(shù)據(jù)報(bào)協(xié)議,在網(wǎng)絡(luò)中它與TCP協(xié)議一樣用于處理數(shù)據(jù)包,是一種無(wú)連接的協(xié)議。在OSI模型中,處于傳輸層,是IP協(xié)議的上層協(xié)議。UDP有不提供數(shù)據(jù)包分組、組裝和不能對(duì)數(shù)據(jù)包進(jìn)行排序的缺點(diǎn),也就是說(shuō),當(dāng)報(bào)文發(fā)送之后,是無(wú)法得知其是否安全完整到達(dá)的。
UDP協(xié)議的主要作用是將網(wǎng)絡(luò)數(shù)據(jù)流量壓縮成數(shù)據(jù)包的形式。一個(gè)典型的數(shù)據(jù)包就是一個(gè)二進(jìn)制數(shù)據(jù)的傳輸單位。每一個(gè)數(shù)據(jù)包的前8個(gè)字節(jié)用來(lái)包含報(bào)頭信息,剩余字節(jié)則用來(lái)包含具體的傳輸數(shù)據(jù)。
UDP報(bào)頭由4個(gè)域組成,其中每個(gè)域各占用2個(gè)字節(jié),具體如下:源端口號(hào)、目標(biāo)端口號(hào)、數(shù)據(jù)報(bào)長(zhǎng)度、校驗(yàn)值。其數(shù)據(jù)結(jié)構(gòu)如下:
UDP協(xié)議使用端口號(hào)為不同的應(yīng)用保留其各自的數(shù)據(jù)傳輸通道。UDP和TCP協(xié)議正是采用這一機(jī)制實(shí)現(xiàn)對(duì)同一時(shí)刻內(nèi)多項(xiàng)應(yīng)用同時(shí)發(fā)送和接收數(shù)據(jù)的支持。數(shù)據(jù)發(fā)送一方(可以是客戶端或服務(wù)器端)將UDP數(shù)據(jù)包通過(guò)源端口發(fā)送出去,而數(shù)據(jù)接收一方則通過(guò)目標(biāo)端口接收數(shù)據(jù)。有的網(wǎng)絡(luò)應(yīng)用只能使用預(yù)先為其預(yù)留或注冊(cè)的靜態(tài)端口;而另外一些網(wǎng)絡(luò)應(yīng)用則可以使用未被注冊(cè)的動(dòng)態(tài)端口。因?yàn)閁DP報(bào)頭使用兩個(gè)字節(jié)存放端口號(hào),所以端口號(hào)的有效范圍是從0到65535。一般來(lái)說(shuō),大于49151的端口號(hào)都代表動(dòng)態(tài)端口。
數(shù)據(jù)報(bào)的長(zhǎng)度是指包括報(bào)頭和數(shù)據(jù)部分在內(nèi)的總字節(jié)數(shù)。因?yàn)閳?bào)頭的長(zhǎng)度是固定的,所以該域主要被用來(lái)計(jì)算可變長(zhǎng)度的數(shù)據(jù)部分。數(shù)據(jù)報(bào)的最大長(zhǎng)度根據(jù)操作環(huán)境的不同而各異。從理論上說(shuō),包含報(bào)頭在內(nèi)的數(shù)據(jù)報(bào)的最大長(zhǎng)度為65535字節(jié)。不過(guò),一些實(shí)際應(yīng)用往往會(huì)限制數(shù)據(jù)報(bào)的大小,有時(shí)會(huì)降低到8192字節(jié)。
UDP協(xié)議使用報(bào)頭中的校驗(yàn)值來(lái)保證數(shù)據(jù)的安全。校驗(yàn)值首先在數(shù)據(jù)發(fā)送方通過(guò)特殊的算法計(jì)算得出,在傳遞到接收方之后,還需要再重新計(jì)算。如果某個(gè)數(shù)據(jù)報(bào)在傳輸過(guò)程中被第三方篡改或者由于線路噪音等原因受到損壞,發(fā)送和接收方的校驗(yàn)計(jì)算值將不會(huì)相符,由此UDP協(xié)議可以檢測(cè)是否出錯(cuò)。
2 、 UDP****客戶端設(shè)計(jì)
前面我們簡(jiǎn)要的介紹了UDP協(xié)議及其數(shù)據(jù)報(bào),接下來(lái)我們將考慮怎么實(shí)現(xiàn)基于UDP協(xié)議的客戶端。
首先,我們來(lái)看一看與UDP相關(guān)的API函數(shù),并對(duì)它們作一個(gè)初步的介紹,應(yīng)為我們需要使用它們來(lái)實(shí)現(xiàn)我們的應(yīng)用。函數(shù)及說(shuō)明如下:
我們已經(jīng)了解了UDP服務(wù)器的實(shí)現(xiàn)步驟,接下來(lái)我們說(shuō)明一下UDP客戶端的實(shí)現(xiàn)步驟。
首先,依然是創(chuàng)建一個(gè)新的UDP控制塊。
接下來(lái),建立與服務(wù)器的連接,配置包括服務(wù)器的地址、端口等信息。
接下來(lái),如果連接無(wú)問(wèn)題,則注冊(cè)客戶端回調(diào)函數(shù)。與服務(wù)器端的實(shí)現(xiàn)一樣,其復(fù)雜程度與需要實(shí)現(xiàn)的功能相關(guān)。我們只是實(shí)現(xiàn)一個(gè)簡(jiǎn)單UDP客戶端,所以我們向服務(wù)器發(fā)送固定的信息,收到回復(fù)后繼續(xù)發(fā)送對(duì)應(yīng)的信息。
最后,由于客戶端是對(duì)話的發(fā)起方,所以在注冊(cè)完回調(diào)函數(shù)后,客戶端要發(fā)起首次對(duì)話。
3 、 UDP****客戶端實(shí)現(xiàn)
對(duì)UDP服務(wù)器端的實(shí)現(xiàn),我們依然將器分為兩方面內(nèi)容:一是,UDP客戶端的初始化配置部分;二是,UDP客戶端的具體實(shí)現(xiàn)內(nèi)容,也就是回調(diào)函數(shù)的內(nèi)容。
首先實(shí)現(xiàn)UDP客戶端的初始化配置部分。定義新的UDP控制塊,連接到指定服務(wù)器的地址及端口,同樣由于我們的驗(yàn)證比較簡(jiǎn)單我們采用回環(huán)服務(wù)器端口。然后注冊(cè)回調(diào)函數(shù),發(fā)起客戶端首次通訊。具體代碼如下:
1 /* UDP客戶端初始化配置 */
2 void UDP_Client_Initialization(void)
3 {
4 ip_addr_t DestIPaddr;
5 err_t err;
6 struct udp_pcb *upcb;
7 char data[]="This is a Client.";
8
9 /* 設(shè)置服務(wù)器端的IP地址 */
10 IP4_ADDR( &DestIPaddr,udpServerIP[0],udpServerIP[1],udpServerIP[2],udpServerIP[3]);
11
12 /* 創(chuàng)建一個(gè)新的UDP控制塊 */
13 upcb = udp_new();
14
15 if (upcb!=NULL)
16 {
17 /* 服務(wù)器端地址、端口配置 */
18 err= udp_connect(upcb, &DestIPaddr, UDP_ECHO_SERVER_PORT);
19
20 if (err == ERR_OK)
21 {
22 /* 注冊(cè)回調(diào)函數(shù) */
23 udp_recv(upcb, UDPClientCallback, NULL);
24 /**數(shù)據(jù)發(fā)送,第一次連接時(shí)客戶端發(fā)送數(shù)據(jù)至服務(wù)器端,發(fā)送函數(shù)中會(huì)遍歷查找源IP地址的配置,如果源IP地址未配置,則數(shù)據(jù)發(fā)送失敗。該處出現(xiàn)的問(wèn)題在后面總結(jié)中提到了**/
25 UdpClientSendPacket(upcb,data);
26 }
27 }
28 }
其次實(shí)現(xiàn)UDP客戶端的具體實(shí)現(xiàn)內(nèi)容。由于我們實(shí)現(xiàn)的簡(jiǎn)單的響應(yīng)客戶端,所以我們只是給服務(wù)器回復(fù)相同的內(nèi)容。
1 /* 定義UDP客戶端數(shù)據(jù)處理回調(diào)函數(shù) */
2 static void UDPClientCallback(void *arg,struct udp_pcb *upcb,struct pbuf *p,const ip_addr_t *addr,u16_t port)
3 {
4 udp_send(upcb, p); //數(shù)據(jù)回顯
5
6 pbuf_free(p);
7 }
8
9 /* 客戶端數(shù)據(jù)發(fā)送函數(shù) */
10 void UdpClientSendPacket(struct udp_pcb *upcb,char* data)
11 {
12 struct pbuf *p;
13
14 /* 分配內(nèi)存空間 */
15 p = pbuf_alloc(PBUF_TRANSPORT,strlen((char*)data), PBUF_POOL);
16
17 if (p != NULL)
18 {
19
20 /* 復(fù)制數(shù)據(jù)到pbuf */
21 pbuf_take(p, (char*)data, strlen((char*)data));
22
23 /* 發(fā)送數(shù)據(jù) */
24 udp_send(upcb, p); //發(fā)送數(shù)據(jù)
25
26 /* 釋放pbuf */
27 pbuf_free(p);
28 }
29 }
當(dāng)然,如果我們不想人云亦云的回復(fù)服務(wù)器,則可以編輯我們自己的數(shù)據(jù)包然后發(fā)送回去。所以我們想要實(shí)現(xiàn)復(fù)雜的應(yīng)用時(shí),只需要重新編寫合適的回調(diào)函數(shù)就可以了!
4 、結(jié)論
我們完成了簡(jiǎn)單的,基于RAW API的UDP客戶端,其本身并不復(fù)雜。同樣的我們使用網(wǎng)絡(luò)軟件測(cè)試其功能,我們?cè)?a target="_blank">電腦上建立一個(gè)服務(wù)器端,然后通過(guò)我們這個(gè)客戶端去連接它。能夠進(jìn)行連接并發(fā)送接受數(shù)據(jù),說(shuō)明我們這個(gè)客戶端的設(shè)計(jì)是符合要求的。
至此我們完成了UDP客戶端及服務(wù)器的實(shí)現(xiàn),后續(xù)我們將在次基礎(chǔ)上實(shí)現(xiàn)更為復(fù)雜的應(yīng)用。
-
API
+關(guān)注
關(guān)注
2文章
1545瀏覽量
63195 -
UDP
+關(guān)注
關(guān)注
0文章
329瀏覽量
34328 -
客戶端
+關(guān)注
關(guān)注
1文章
296瀏覽量
16915 -
RAW
+關(guān)注
關(guān)注
0文章
21瀏覽量
3928
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
請(qǐng)問(wèn)如何獲取遠(yuǎn)程客戶端的IP和端口號(hào)進(jìn)行UDP廣播?
請(qǐng)教網(wǎng)絡(luò)傳輸中的奇怪問(wèn)題:UDP傳輸有問(wèn)題、TCP客戶端傳輸可行。
TCPIP_UDP_Bind()阻止udp客戶端發(fā)送UDP數(shù)據(jù)包
請(qǐng)問(wèn)ESP8266的UDP到底區(qū)不區(qū)分服務(wù)器和客戶端?
如何獲取連接的UDP客戶端的遠(yuǎn)程MAC地址Harmony 1.09
請(qǐng)問(wèn)RN1810是否可以同時(shí)激活UDP客戶端和UDP服務(wù)器或TCP客戶端?
如何使用Socket實(shí)現(xiàn)UDP客戶端?
LWIP的RAW API UDP通信過(guò)程是如何實(shí)現(xiàn)的
網(wǎng)絡(luò)調(diào)試和串口調(diào)試集合UDP TCP客戶端和TCP服務(wù)器端應(yīng)用程序免費(fèi)下載

基于RAW API的UDP服務(wù)器設(shè)計(jì)

基于LwIP的TCP客戶端設(shè)計(jì)

評(píng)論