25.1 UDP協(xié)議概述
UDP協(xié)議是TCP/IP協(xié)議棧中傳輸層協(xié)議,是一個(gè)簡(jiǎn)單的面向數(shù)據(jù)報(bào)的協(xié)議,在傳輸層中還有一個(gè)TCP協(xié)議,UDP不提供數(shù)據(jù)包分組,組裝,無法對(duì)數(shù)據(jù)包進(jìn)行排序,當(dāng)報(bào)文發(fā)送出去之后無法知道是否安全,完整的到達(dá),但是由于UDP不屬于連接性協(xié)議,所以消耗資源小,處理速度快,通常用于音頻,視頻和普通數(shù)據(jù)傳輸中,UDP數(shù)據(jù)包結(jié)構(gòu)如下圖所示。
端口號(hào)表示發(fā)送和接收進(jìn)程,UDP使用端口號(hào)為不同的應(yīng)用保留各自的數(shù)據(jù)傳輸通道,UDP和TCP都是采用端口號(hào)的形式對(duì)同一時(shí)刻多個(gè)應(yīng)用同時(shí)發(fā)送和接受數(shù)據(jù),而數(shù)據(jù)接收方則通過目標(biāo)端口接受數(shù)據(jù),有的網(wǎng)絡(luò)只能使用預(yù)先預(yù)留或注冊(cè)的靜態(tài)端口,而一些網(wǎng)絡(luò)可以使用沒有被注冊(cè)的動(dòng)態(tài)端口,由于UDP包頭使用兩個(gè)字節(jié)存放端口號(hào),所以端口的有效范圍0~65535,一般,大于49151的端口號(hào)都代表動(dòng)態(tài)端口。
數(shù)據(jù)包的長(zhǎng)度指的是包括包頭和數(shù)據(jù)部分在內(nèi)的總字節(jié)數(shù),由于包頭的長(zhǎng)度固定,所以這個(gè)區(qū)域主要用于計(jì)算可變長(zhǎng)度的數(shù)據(jù)部分,數(shù)據(jù)包的最大長(zhǎng)度根據(jù)操作環(huán)境選擇,理論上說,包括包頭在內(nèi)的數(shù)據(jù)報(bào)文最大長(zhǎng)度為65535字節(jié)。
UDP通過包頭中的校驗(yàn)和來保證數(shù)據(jù)的完整性,校驗(yàn)和首先在數(shù)據(jù)發(fā)送方通過特殊的算法計(jì)算出,傳遞到接收方之后,需要重新計(jì)算,如果某個(gè)數(shù)據(jù)在輸出過程中被篡改或某種原因損壞,那么發(fā)送方和接收方的校驗(yàn)和就會(huì)不一致,因此,UDP協(xié)議具有檢測(cè)報(bào)文是否出錯(cuò)的能力。
udp.c和udp.h這兩個(gè)文件就是負(fù)責(zé)實(shí)現(xiàn)UDP傳輸協(xié)議的文件,與UDP報(bào)文處理有關(guān)的函數(shù)之間的關(guān)系如下圖所示。
LWIP協(xié)議中API編程方式是基于回調(diào)機(jī)制的,在我們初始化應(yīng)用的時(shí)候必須為內(nèi)核中不同的事件注冊(cè)給出對(duì)應(yīng)的回調(diào)函數(shù),當(dāng)對(duì)應(yīng)的事件發(fā)生后這些回調(diào)函數(shù)就會(huì)被調(diào)用,udp.c中常用的API功能函數(shù)如下表所示。
API函數(shù) | 函數(shù)功能 |
---|---|
udp_new | 新建一個(gè)UDP的PCB塊 |
udp_remove | 將一個(gè)PCB控制塊從鏈表中刪除,并釋放這個(gè)控制塊的內(nèi)存 |
udp_bind | 為UDP的PCN控制塊綁定一個(gè)本地IP地址和端口號(hào) |
udp_connect | 連接到指定IP地址主機(jī)的指定端口上 |
udp_disconnent | 斷開連接,將控制塊設(shè)置為非連接狀態(tài) |
udp_send | 通過一個(gè)PCB控制塊發(fā)送數(shù)據(jù) |
udp_recv | 需要?jiǎng)?chuàng)建一個(gè)回調(diào)函數(shù),當(dāng)接受到數(shù)據(jù)的時(shí)候被調(diào)用 |
25.2 應(yīng)用編寫
在LWIP/app/udp_demo目錄下創(chuàng)建udp_demo.c和udp_demo.h文件。
25.2.1 udp_demo.c代碼編寫
#include "udp_demo.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "malloc.h"
#include "string.h"
#include "comm.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
//UDP 測(cè)試全局狀態(tài)標(biāo)記變量
//bit6:數(shù)據(jù)接收狀態(tài)
//bit5:連接狀態(tài)
u8 udp_demo_flag;
//設(shè)置遠(yuǎn)端IP地址
void udp_demo_set_remoteip()
{
u8 *tbuf ;
LCD_Clear( WHITE ) ;
POINT_COLOR = RED ;
tbuf = mymalloc( SRAMIN, 100 ) ; //申請(qǐng)內(nèi)存
if( tbuf==NULL )
return ;
//前三個(gè)IP保持和DHCP得到的IP一致
lwipdev.remoteip[ 0 ] = lwipdev.ip[ 0 ] ;
lwipdev.remoteip[ 1 ] = lwipdev.ip[ 1 ] ;
lwipdev.remoteip[ 2 ] = lwipdev.ip[ 2 ] ;
lwipdev.remoteip[ 3 ] = 113 ;
sprintf( ( char* )tbuf, "Remote IP:%d.%d.%d.", lwipdev.remoteip[0], lwipdev.remoteip[1], lwipdev.remoteip[2] ) ;
LCD_ShowString( 30, 150, tbuf ) ; //遠(yuǎn)端IP
myfree( SRAMIN, tbuf ) ;
}
// UDP接收回調(diào)函數(shù)
u8 udp_demo_recvbuf[ UDP_DEMO_RX_BUFSIZE ] ; //UDP接收數(shù)據(jù)緩沖區(qū)
void udp_demo_recv( void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port )
{
u32 data_len=0 ;
struct pbuf *q ;
//接收到不為空的數(shù)據(jù)時(shí)
if( p!=NULL )
{
memset( udp_demo_recvbuf, 0, UDP_DEMO_RX_BUFSIZE ) ; //數(shù)據(jù)接收緩沖區(qū)清零
//遍歷完整個(gè)pbuf鏈表
for( q=p; q!=NULL; q=q->next )
{
//拷貝數(shù)據(jù)
if( q->len>( UDP_DEMO_RX_BUFSIZE-data_len ) )
memcpy( udp_demo_recvbuf+data_len, q->payload, UDP_DEMO_RX_BUFSIZE-data_len ) ;
else
memcpy( udp_demo_recvbuf+data_len, q->payload, q->len ) ;
data_len += q->len ;
//超出TCP客戶端接收數(shù)組,跳出
if( data_len>UDP_DEMO_RX_BUFSIZE )
break ;
}
upcb->remote_ip = *addr ; //記錄遠(yuǎn)程主機(jī)的IP地址
upcb->remote_port = port ; //記錄遠(yuǎn)程主機(jī)的端口號(hào)
lwipdev.remoteip[ 0 ] = upcb->remote_ip.addr&0xFF ; //IADDR4
lwipdev.remoteip[ 1 ] = ( upcb->remote_ip.addr>>8 )&0xFF ; //IADDR3
lwipdev.remoteip[ 2 ] = ( upcb->remote_ip.addr>>16 )&0xFF ; //IADDR2
lwipdev.remoteip[ 3 ] = ( upcb->remote_ip.addr>>24 )&0xFF ; //IADDR1
udp_demo_flag |= 1<<6 ; //標(biāo)記接收到數(shù)據(jù)了
pbuf_free( p ) ; //釋放內(nèi)存
}
else
{
udp_disconnect( upcb ) ;
LCD_Clear( WHITE ) ; //清屏
udp_demo_flag &= ~( 1<<5 ) ; //標(biāo)記連接斷開
}
}
// UDP服務(wù)器發(fā)送數(shù)據(jù)
const u8 *tcp_demo_sendbuf="STM32F103 UDP send data\\r\\n";
void udp_demo_senddata( struct udp_pcb *upcb )
{
struct pbuf *ptr ;
ptr = pbuf_alloc( PBUF_TRANSPORT, strlen( ( char* )tcp_demo_sendbuf ), PBUF_POOL ) ;//申請(qǐng)內(nèi)存
if( ptr )
{
ptr->payload = ( void* )tcp_demo_sendbuf ;
udp_send( upcb, ptr ) ; //udp發(fā)送數(shù)據(jù)
pbuf_free( ptr ) ; //釋放內(nèi)存
}
}
//關(guān)閉UDP連接
void udp_demo_connection_close( struct udp_pcb *upcb )
{
udp_disconnect( upcb ) ;
udp_remove( upcb ) ; //斷開UDP連接
udp_demo_flag &= ~( 1<<5 ) ; //標(biāo)記連接斷開
LCD_Clear( WHITE ) ; //清屏
}
// UDP測(cè)試
void udp_demo_test()
{
err_t err ;
struct udp_pcb *udppcb ; //定義一個(gè)TCP服務(wù)器控制塊
struct ip_addr rmtipaddr ; //遠(yuǎn)端ip地址
u8 *tbuf ;
u8 res=0 ;
udp_demo_set_remoteip() ; //先選擇IP
LCD_Clear( WHITE ) ; //清屏
tbuf = mymalloc( SRAMIN, 200 ) ; //申請(qǐng)內(nèi)存
//內(nèi)存申請(qǐng)失敗了,直接退出
if( tbuf==NULL )
return ;
sprintf( ( char* )tbuf, "Local IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
LCD_ShowString( 30, 150, tbuf ) ; //服務(wù)器IP
sprintf( ( char* )tbuf, "Remote IP:%d.%d.%d.%d", lwipdev.remoteip[0], lwipdev.remoteip[1], lwipdev.remoteip[2], lwipdev.remoteip[3] ) ;
LCD_ShowString( 30, 170, tbuf ) ; //遠(yuǎn)端IP
sprintf( ( char* )tbuf, "Remote Port:%d", UDP_DEMO_PORT ) ;
LCD_ShowString( 30, 190, tbuf ) ; //客戶端端口號(hào)
LCD_ShowString( 30, 210, "STATUS:Disconnected" ) ;
udppcb = udp_new() ;
//創(chuàng)建成功
if( udppcb )
{
IP4_ADDR( &rmtipaddr, lwipdev.remoteip[0], lwipdev.remoteip[1], lwipdev.remoteip[2], lwipdev.remoteip[3] ) ;
err = udp_connect( udppcb, &rmtipaddr, UDP_DEMO_PORT ) ; //UDP客戶端連接到指定IP地址和端口
if( err==ERR_OK )
{
err = udp_bind( udppcb, IP_ADDR_ANY, UDP_DEMO_PORT ) ; //綁定本地IP地址與端口號(hào)
//綁定完成
if( err==ERR_OK )
{
udp_recv( udppcb, udp_demo_recv, NULL ) ; //注冊(cè)接收回調(diào)函數(shù)
LCD_ShowString( 30, 210, "STATUS:Connected " ) ; //標(biāo)記連接上了
udp_demo_flag |= 1<<5 ; //標(biāo)記已經(jīng)連接上
LCD_ShowString( 30, 230, "Receive Data:" ) ; //提示消息
}
else
res = 1 ;
}
else
res = 1 ;
}
else
res = 1 ;
while( res==0 )
{
//是否收到數(shù)據(jù)
if( udp_demo_flag&1<<6 )
{
LCD_ShowString( 30, 250, udp_demo_recvbuf ) ; //顯示接收到的數(shù)據(jù)
udp_demo_senddata( udppcb ) ; //發(fā)送數(shù)據(jù)
udp_demo_flag &= ~( 1<<6 ) ; //標(biāo)記數(shù)據(jù)已經(jīng)被處理了
}
lwip_periodic_handle() ;
lwip_pkt_handle() ;
delay_ms( 2 ) ;
}
udp_demo_connection_close( udppcb ) ;
myfree( SRAMIN, tbuf ) ;
}
25.2.2 udp_demo.h代碼編寫
#ifndef _UDP_DEMO_H_
#define _UDP_DEMO_H_
#include "sys.h"
#define UDP_DEMO_RX_BUFSIZE 2000 //定義udp最大接收數(shù)據(jù)長(zhǎng)度
#define UDP_DEMO_PORT 8089 //定義udp連接的端口
void udp_demo_test( void ) ; //UDP測(cè)試
#endif
25.2.3 主函數(shù)代碼編寫
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "tim.h"
#include "lcd.h"
#include "malloc.h"
#include "dm9000.h"
#include "lwip/netif.h"
#include "comm.h"
#include "lwipopts.h"
#include "udp_demo.h"
int main()
{
u8 buf[ 30 ];
STM32_Clock_Init( 9 ) ; //系統(tǒng)時(shí)鐘設(shè)置
SysTick_Init( 72 ) ; //延時(shí)初始化
USART1_Init( 72, 115200 ) ; //串口初始化為115200
LCD_Init() ; //初始化LCD
TIM3_Init( 1000, 719 ) ; //定時(shí)器3頻率為100hz
my_mem_init( SRAMIN ) ; //初始化內(nèi)部?jī)?nèi)存池
while( lwip_comm_init() ) ; //lwip初始化
//等待DHCP獲取成功/超時(shí)溢出
while( ( lwipdev.dhcpstatus!=2 )&&( lwipdev.dhcpstatus!=0xFF ) )
{
lwip_periodic_handle() ; //LWIP內(nèi)核需要定時(shí)處理的函數(shù)
lwip_pkt_handle() ;
}
POINT_COLOR=RED;
LCD_ShowString( 30, 110, "LWIP Init Successed" ) ;
//打印動(dòng)態(tài)IP地址
if( lwipdev.dhcpstatus==2 )
sprintf( ( char* )buf, "DHCP IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
//打印靜態(tài)IP地址
else
sprintf( ( char* )buf, "Static IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
LCD_ShowString( 30, 130, buf ) ;
//得到網(wǎng)速
if( ( DM9000_Get_SpeedAndDuplex()&0x02 )==0x02 )
LCD_ShowString( 30, 150, "Ethernet Speed:10M" ) ;
else
LCD_ShowString( 30, 150, "Ethernet Speed:100M" ) ;
while( 1 )
{
udp_demo_test();
lwip_periodic_handle() ;
lwip_pkt_handle() ;
delay_ms( 2 ) ;
}
}
25.3 實(shí)驗(yàn)結(jié)果
-
數(shù)據(jù)傳輸
+關(guān)注
關(guān)注
9文章
1928瀏覽量
64717 -
UDP協(xié)議
+關(guān)注
關(guān)注
0文章
69瀏覽量
12718 -
傳輸層協(xié)議
+關(guān)注
關(guān)注
0文章
6瀏覽量
1284
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論