uip UDP 服務器廣播模式(客戶端可以任意端口,并且主動向客戶端發(fā)送數(shù)據(jù))
目前移植uip,發(fā)現(xiàn)UDP 服務器模式下,必須指定本地端口以及客戶端端口,否則只能講客戶端端口設置為0,才能接收任意端口的數(shù)據(jù),但是無法發(fā)送數(shù)據(jù),因為此時客戶端端口設置為0了,我通過將原始數(shù)據(jù)包中的客戶端端口保存下來,并且在發(fā)送的時候將客戶端端口替換為指定的端口,發(fā)送完成之后又設置為0,這樣就實現(xiàn)了向任意客戶端端口發(fā)送數(shù)據(jù).
uip.c
????if(uip_udp_conn->lport?!=?0?&& ???????UDPBUF->destport?==?uip_udp_conn->lport?&& ???????(uip_udp_conn->rport?==?0?|| ????????UDPBUF->srcport?==?uip_udp_conn->rport)?&& ???????(uip_ipaddr_cmp(uip_udp_conn->ripaddr,?all_zeroes_addr)?|| uip_ipaddr_cmp(uip_udp_conn->ripaddr,?all_ones_addr)?|| uip_ipaddr_cmp(BUF->srcipaddr,?uip_udp_conn->ripaddr)))?{
?(uip_udp_conn->rport?==?0?|| ????????UDPBUF->srcport?==?uip_udp_conn->rport)?&&
這句就限制了客戶端端口為0或者指定端口
//udp_server.c
/************************************************************************************************************* ?*?文件名: udp_server.h ?*?功能: uIP?UDP服務器相關函數(shù) ?*?作者: cp1300@139.com ?*?創(chuàng)建時間: 2014-06-04 ?*?最后修改時間: 2014-06-04 ?*?詳細: UDP服務器相關函數(shù) *************************************************************************************************************/ #include?"SYSTEM.h" #include?"tapdev.h" #include?"uip.h" #include#include #include?"uIP_user.h" #include?"udp_server.h" #include?"appconfig.h" u16?UDP_ServerPort?=?UDP_SERVER_PORT; //UDP服務器本地端口,用于新數(shù)據(jù)端口識別 UIP_USER?udp_server; //UDP?服務器數(shù)據(jù)結構 static?bool?isAnyPort?=?FALSE; //客戶端任意端口標志 /************************************************************************************************************************* *?函數(shù) : void?udp_server_connected(u16?ServerPort,u16?ClientPort) *?功能 : 建立一個UDP服務器(廣播方式) *?參數(shù) : ServerPort:服務器本地端口,ClientPort:客戶端端口,0:任意端口;非0:指定端口 *?返回 : 無 *?依賴 : uip *?作者 : cp1300@139.com *?時間 : 2014-06-04 *?最后修改時間 :? 2014-06-05 *?說明 :? 必須放在UDP客戶端初始化之前 *************************************************************************************************************************/ void?udp_server_connected(u16?ServerPort,u16?ClientPort) { UDP_ServerPort?=?ServerPort; //本地端口 uip_listen(HTONS(ServerPort)); uip_udp_bind(&uip_udp_conns[0],?htons(ServerPort)); //綁定本地端口 udp_server.RxLen?=?0; udp_server.TxLen?=?0; udp_server.ServerPort?=?ServerPort; //服務器端口 if(ClientPort?!=?0) //指定端口 { uip_udp_conns[0].rport?=?HTONS(ClientPort); udp_server.ClientPort?=?ClientPort; isAnyPort?=?FALSE; //客戶端指定端口 } else { uip_udp_conns[0].rport?=?0; isAnyPort?=?TRUE; //客戶端任意端口 } } /************************************************************************************************************************* *?函數(shù) : void?udp_server_appcall(void) *?功能 : 服務器回調函數(shù),用于uip處理數(shù)據(jù) *?參數(shù) : 無 *?返回 : 無 *?依賴 : uip *?作者 : cp1300@139.com *?時間 : 2014-06-04 *?最后修改時間 :? 2014-06-05 *?說明 :? 無 *************************************************************************************************************************/ void?udp_server_appcall(void) { if?(uip_newdata()) ????{ if(uip_datalen()?>?UIP_RX_BUFF_ZISE)?uip_len?=?UIP_RX_BUFF_ZISE; //限制大小 memcpy(udp_server.RxBuff,?uip_appdata,?uip_len); //復制接收的數(shù)據(jù)到接收緩沖區(qū) udp_server.RxLen?=?uip_len; //存儲接收數(shù)據(jù)長度 udp_server.ClientPort?=?(u16)(uip_buf[34]<UIP_TX_BUFF_ZISE)?len?=?UIP_TX_BUFF_ZISE; memcpy(udp_server.TxBuff,?pBuff,?len); udp_server.TxLen?=?len; uip_udp_conns[0].rport?=?HTONS(ClientPort); //暫時將客戶端端口設置為上一次發(fā)送數(shù)據(jù)的客戶端端口 } /************************************************************************************************************************* *?函數(shù) : void?udp_ServerSendEndCallBack(u16?conn) *?功能 : UDP發(fā)送數(shù)據(jù)完成回調函數(shù),目前只支持一個服務器端口 *?參數(shù) : pBuff:發(fā)送數(shù)據(jù)緩沖區(qū),len:發(fā)送數(shù)據(jù)長度,ClientPort:客戶端端口 *?返回 : 無 *?依賴 : uip *?作者 : cp1300@139.com *?時間 : 2014-06-04 *?最后修改時間 :? 2014-06-05 *?說明 :? 由于UDP服務器的客戶端IP設置為0后可以接收任意端口發(fā)來的數(shù)據(jù),但是卻無法發(fā)送數(shù)據(jù) 到0端口,因此在發(fā)送前將客戶端端口設置為實際端口,發(fā)送完成后修改為0 *************************************************************************************************************************/ void?udp_ServerSendEndCallBack(u16?conn) { if((conn?==?0)?&&?(isAnyPort?==?TRUE)) { uip_udp_conns[conn].rport?=?0; //將端口設置為0 } }
//udp_server.h
/************************************************************************************************************* ?*?文件名: udp_server.h ?*?功能: uIP?UDP服務器相關函數(shù) ?*?作者: cp1300@139.com ?*?創(chuàng)建時間: 2014-06-04 ?*?最后修改時間: 2014-06-04 ?*?詳細: UDP服務器相關函數(shù) *************************************************************************************************************/ #ifndef?_UDP_SERVER_H_ #define?_UDP_SERVER_H_ #include?"tcp.h" #include?"uip.h" #include?"system.h" #include?"uIP_user.h" extern?UIP_USER?udp_server; //UDP?服務器數(shù)據(jù)結構 extern?u16?UDP_ServerPort; //UDP服務器本地端口 void?udp_server_connected(u16?ServerPort,u16?ClientPort); //建立一個UDP服務器(廣播方式) void?udp_server_appcall(void); //服務器回調函數(shù),用于uip處理數(shù)據(jù) void?udp_ServerSendDataPackage(u8?*pBuff,?u16?len,u16?ClientPort); //UDP?服務器發(fā)送數(shù)據(jù) void?udp_ServerSendEndCallBack(u16?conn); //UDP發(fā)送數(shù)據(jù)完成回調函數(shù) #endif?//_UDP_SERVER_H_
//結構體定義
//用戶連接數(shù)據(jù)結構 #define?UIP_RX_BUFF_ZISE 512 //接收數(shù)據(jù)緩沖區(qū)大小 #define?UIP_TX_BUFF_ZISE 512 //發(fā)送數(shù)據(jù)緩沖區(qū)大小 typedef?struct { u16?RxLen; //接收數(shù)據(jù)長度 u16 TxLen; //發(fā)送數(shù)據(jù)長度 u16?ClientPort; //客戶端端口 u16 ServerPort; //服務器端口 u8 RxBuff[UIP_RX_BUFF_ZISE]; //接收緩沖區(qū) u8 TxBuff[UIP_TX_BUFF_ZISE]; //接收緩沖區(qū) }UIP_USER;
//配置定義
#define?DHCP_TIME_OUT 60 //DHCP獲取超時時間,單位S #define?TCP_LINK_SERVER_TIME_OUT 10 //連接服務器超時時間,單位S #define?TCP_LINK_SERVER_CNT 5 //連接服務器重試次數(shù) #define?TCP_CLIENT_PORT_AUTO 1 //客戶端端口隨機分配 #define?TCP_CLIENT_DEFAULT_PORT 2400 //客戶端默認端口 #define?TCP_SERVER_DEFAULT_IP 192,168,16,104 //服務器默認IP地址 #define?TCP_SERVER_DEFAULT_PORT 8888 //服務器默認端口 #define?TCP_SEND_TIME_OUT 5 //數(shù)據(jù)發(fā)送超時時間,單位S #define?UDP_LOCAL_PORT 8000 //UDP連接本地端口 #define?UDP_REMOTE_PORT 8899 //UDP連接遠程端口 #define?UDP_SERVER_PORT 8100 //UDP服務器本地端口
//數(shù)據(jù)端口調度
//UDP應用接口函數(shù)(UIP_UDP_APPCALL) void?udp_appcall(void) { switch(uip_udp_conn->lport)//本地監(jiān)聽端口 { //用于DHCP case?HTONS(67): dhcpc_appcall();break; case?HTONS(68): ?dhcpc_appcall();break; default:? { if(uip_udp_conn->lport?==?HTONS(UDP_ClinetPort)) //UDP客戶端 { udp_client_appcall(); } else?if(uip_udp_conn->lport?==?HTONS(UDP_ServerPort)) //UDP服務器 { udp_server_appcall(); } }break; } ?????? }
//UDP調度處理,必須在數(shù)據(jù)發(fā)送完成后調用自定義的回調函數(shù)
for(i?=?0;?i?<?UIP_UDP_CONNS;?i++) { //只處理發(fā)送事件 uip_udp_periodic(i); //處理UDP通信事件 //當上面的函數(shù)執(zhí)行后,如果需要發(fā)送數(shù)據(jù),則全局變量uip_len>0 //需要發(fā)送的數(shù)據(jù)在uip_buf,?長度是uip_len?(這是2個全局變量) if(uip_len?>?0) { LED2?=?~?LED2; uip_arp_out();//加以太網(wǎng)頭結構,在主動連接時可能要構造ARP請求 tapdev_send();//發(fā)送數(shù)據(jù)到以太網(wǎng) udp_ServerSendEndCallBack(i); //數(shù)據(jù)發(fā)送完成后一定要調用回調函數(shù) break; } }
調用這個實現(xiàn)將客戶端端口設置為0,這樣就可以接受來自任意端口的數(shù)據(jù)
udp_ServerSendEndCallBack(i); //數(shù)據(jù)發(fā)送完成后一定要調用回調函數(shù)
//初始化并處理UDP服務器數(shù)據(jù)
//實現(xiàn)收到后立即返回數(shù)據(jù)
udp_server_connected(UDP_SERVER_PORT,?0); //新建UDP服務器,客戶端任意端口
//UDP服務器數(shù)據(jù)處理 if(udp_server.RxLen?>?0) { uart_printf("服務器端口:%drn",udp_server.ServerPort); uart_printf("客戶端端口:%drn",udp_server.ClientPort); uart_printf("UDP?Server?Rx(%dB):%srn",udp_server.RxLen,(char*)udp_server.RxBuff); udp_ServerSendDataPackage(udp_server.RxBuff,?udp_server.RxLen,?udp_server.ClientPort); udp_server.RxLen?=?0; }
//仿真結果