亚洲精品久久久久久久久久久,亚洲国产精品一区二区制服,亚洲精品午夜精品,国产成人精品综合在线观看,最近2019中文字幕一页二页

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

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

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

第十三章 W55MH32 UPnP端口轉(zhuǎn)發(fā)示例

W55MH32 ? 來(lái)源:W55MH32 ? 作者:W55MH32 ? 2025-07-24 10:28 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

單芯片解決方案,開(kāi)啟全新體驗(yàn)——W55MH32 高性能以太網(wǎng)單片機(jī)

W55MH32是WIZnet重磅推出的高性能以太網(wǎng)單片機(jī),它為用戶帶來(lái)前所未有的集成化體驗(yàn)。這顆芯片將強(qiáng)大的組件集于一身,具體來(lái)說(shuō),一顆W55MH32內(nèi)置高性能Arm? Cortex-M3核心,其主頻最高可達(dá)216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲(chǔ)與數(shù)據(jù)處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協(xié)議棧、內(nèi)置MAC以及PHY,擁有獨(dú)立的32KB以太網(wǎng)收發(fā)緩存,可供8個(gè)獨(dú)立硬件socket使用。如此配置,真正實(shí)現(xiàn)了All-in-One解決方案,為開(kāi)發(fā)者提供極大便利。

在封裝規(guī)格上,W55MH32提供了兩種選擇:QFN100和QFN68。

W55MH32L采用QFN100封裝版本,尺寸為12x12mm,其資源豐富,專為各種復(fù)雜工控場(chǎng)景設(shè)計(jì)。它擁有66個(gè)GPIO、3個(gè)ADC、12通道DMA、17個(gè)定時(shí)器、2個(gè)I2C、5個(gè)串口、2個(gè)SPI接口(其中1個(gè)帶I2S接口復(fù)用)、1個(gè)CAN、1個(gè)USB2.0以及1個(gè)SDIO接口。如此豐富的外設(shè)資源,能夠輕松應(yīng)對(duì)工業(yè)控制中多樣化的連接需求,無(wú)論是與各類傳感器、執(zhí)行器的通信,還是對(duì)復(fù)雜工業(yè)協(xié)議的支持,都能游刃有余,成為復(fù)雜工控領(lǐng)域的理想選擇。同系列還有QFN68封裝的W55MH32Q版本,該版本體積更小,僅為8x8mm,成本低,適合集成度高的網(wǎng)關(guān)模組等場(chǎng)景,軟件使用方法一致。更多信息和資料請(qǐng)進(jìn)入http://www.w5500.com/網(wǎng)站或者私信獲取。

此外,本W(wǎng)55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應(yīng)用,涵蓋TCP SSL、HTTP SSL以及 MQTT SSL等,為網(wǎng)絡(luò)通信安全再添保障。

為助力開(kāi)發(fā)者快速上手與深入開(kāi)發(fā),基于W55MH32L這顆芯片,WIZnet精心打造了配套開(kāi)發(fā)板。開(kāi)發(fā)板集成WIZ-Link芯片,借助一根USB C口數(shù)據(jù)線,就能輕松實(shí)現(xiàn)調(diào)試、下載以及串口打印日志等功能。開(kāi)發(fā)板將所有外設(shè)全部引出,拓展功能也大幅提升,便于開(kāi)發(fā)者全面評(píng)估芯片性能。

若您想獲取芯片和開(kāi)發(fā)板的更多詳細(xì)信息,包括產(chǎn)品特性、技術(shù)參數(shù)以及價(jià)格等,歡迎訪問(wèn)官方網(wǎng)頁(yè):http://www.w5500.com/,我們期待與您共同探索W55MH32的無(wú)限可能。

wKgZO2iBiBmAe3DyAACpGc5mWX8613.png

第十三章 W55MH32 UPnP端口轉(zhuǎn)發(fā)示例

本篇文章,我們將詳細(xì)介紹如何在W55MH32芯片上面實(shí)現(xiàn)UPnP協(xié)議。使用W55MH32的TOE引擎,我們只需進(jìn)行簡(jiǎn)單的socket編程寄存器讀寫(xiě),便可輕松實(shí)現(xiàn)以太網(wǎng)應(yīng)用。接下來(lái)我們通過(guò)實(shí)戰(zhàn)例程,為大家講解如何使用TOE引擎實(shí)現(xiàn)UPnP協(xié)議的端口轉(zhuǎn)發(fā)功能。

該例程用到的其他網(wǎng)絡(luò)協(xié)議,例如DHCP,請(qǐng)參考相關(guān)章節(jié)。有關(guān)W55MH32的初始化過(guò)程,請(qǐng)參考Network Install章節(jié),這里將不再贅述。

1 UPnP協(xié)議簡(jiǎn)介

UPnP(Universal Plug and Play)協(xié)議是一種支持設(shè)備在局域網(wǎng)中實(shí)現(xiàn)自動(dòng)發(fā)現(xiàn)和通信的網(wǎng)絡(luò)協(xié)議。其端口轉(zhuǎn)發(fā)功能由IGD Profile提供,允許局域網(wǎng)設(shè)備動(dòng)態(tài)請(qǐng)求路由器為其開(kāi)放指定的端口,以實(shí)現(xiàn)外部設(shè)備訪問(wèn)內(nèi)部服務(wù)。這種功能消除了手動(dòng)配置端口轉(zhuǎn)發(fā)的復(fù)雜性,特別適用于需要穿透NAT(網(wǎng)絡(luò)地址轉(zhuǎn)換)環(huán)境的應(yīng)用場(chǎng)景。

IGDInternet Gateway Device,互聯(lián)網(wǎng)網(wǎng)關(guān)設(shè)備)是UPnP(Universal Plug and Play)協(xié)議的一部分,主要用于管理網(wǎng)絡(luò)中的網(wǎng)關(guān)設(shè)備(如路由器)的服務(wù)和資源。IGD擴(kuò)展定義了一套標(biāo)準(zhǔn)接口,允許局域網(wǎng)設(shè)備與網(wǎng)關(guān)設(shè)備通信,動(dòng)態(tài)配置網(wǎng)絡(luò)設(shè)置,例如端口轉(zhuǎn)發(fā)、帶寬管理和連接狀態(tài)查詢等。

2 UPnP協(xié)議特點(diǎn)

自動(dòng)化配置:無(wú)需用戶手動(dòng)設(shè)置,減少了配置錯(cuò)誤的風(fēng)險(xiǎn)。

動(dòng)態(tài)靈活:端口映射規(guī)則可以根據(jù)需求動(dòng)態(tài)添加或刪除。

設(shè)備友好:支持即插即用,簡(jiǎn)化了設(shè)備的聯(lián)網(wǎng)和部署過(guò)程。

跨設(shè)備兼容:UPnP基于標(biāo)準(zhǔn)化協(xié)議,廣泛支持各種設(shè)備和平臺(tái)。

3 UPnP應(yīng)用場(chǎng)景

通過(guò)UPnP端口轉(zhuǎn)發(fā)功能,我們可以使用W55MH32實(shí)現(xiàn)以下功能:

遠(yuǎn)程訪問(wèn):將外部請(qǐng)求轉(zhuǎn)發(fā)到局域網(wǎng)設(shè)備(如NAS、監(jiān)控?cái)z像頭),實(shí)現(xiàn)外部遠(yuǎn)程訪問(wèn)內(nèi)部設(shè)備。

遠(yuǎn)程控制:外部設(shè)備通過(guò)UPnP轉(zhuǎn)換的端口,可以實(shí)現(xiàn)遠(yuǎn)程控制局域網(wǎng)內(nèi)部設(shè)備(智能門(mén)鎖、燈光控制器)。

4 UPnP設(shè)置端口轉(zhuǎn)發(fā)的工作流程

設(shè)備發(fā)現(xiàn):W55MH32通過(guò)SSDP(Simple Service Discovery Protocol)向局域網(wǎng)中發(fā)送組播請(qǐng)求(HTTP M-SEARCH報(bào)文),搜索支持IGD的網(wǎng)關(guān)設(shè)備。

獲取服務(wù)描述:W55MH32訪問(wèn)網(wǎng)關(guān)設(shè)備(路由器)獲取服務(wù)描述文件,了解支持的服務(wù)和接口。

訂閱IGD事件:通過(guò)事件訂閱,W55MH32可以在不主動(dòng)輪詢的情況下,接收實(shí)時(shí)通知。

調(diào)用服務(wù)接口:使用UPnP的SOAT消息調(diào)用IGD提供的端口映射接口。

數(shù)據(jù)交互測(cè)試:外部通過(guò)訪問(wèn)映射的端口及路由器地址和局域網(wǎng)內(nèi)部設(shè)備進(jìn)行通信。

5報(bào)文講解

設(shè)備搜索

上文我們提到,設(shè)備搜索時(shí)使用SSDP協(xié)議,SSDP(Simple Service Discovery Protocol)是 UPnP協(xié)議中的關(guān)鍵協(xié)議,用于設(shè)備發(fā)現(xiàn)和服務(wù)發(fā)布。它通過(guò)HTTP over UDP的形式在局域網(wǎng)內(nèi)廣播和接收?qǐng)?bào)文,采用多播地址 239.255.255.250和端口 1900。

SSDP報(bào)文主要分為以下幾類:

NOTIFY消息(設(shè)備主動(dòng)廣播通知):用于設(shè)備向網(wǎng)絡(luò)通告自己的存在或離線狀態(tài)。

M-SEARCH消息(客戶端主動(dòng)搜索):客戶端發(fā)送搜索請(qǐng)求以發(fā)現(xiàn)設(shè)備或服務(wù)。

HTTP/1.1響應(yīng)消息(設(shè)備對(duì) M-SEARCH的響應(yīng)):設(shè)備對(duì)搜索請(qǐng)求的響應(yīng),提供設(shè)備描述文件的位置及服務(wù)信息。

SSDP報(bào)文基于HTTP協(xié)議,有固定的格式,主要包括以下字段:

HOST:目標(biāo)地址和端口,固定為 239.255.255.250:1900。

MAN:用于標(biāo)識(shí)搜索消息,固定為 "ssdp:discover"(僅在 M-SEARCH中使用)。

MX:最大響應(yīng)時(shí)間,指定設(shè)備在多長(zhǎng)時(shí)間內(nèi)響應(yīng)(單位:秒)。

ST:搜索目標(biāo),標(biāo)識(shí)要查找的設(shè)備類型或服務(wù)類型。

NT:通知類型,表示設(shè)備或服務(wù)的類型(在 NOTIFY消息中使用)。

USN:唯一服務(wù)名稱,設(shè)備或服務(wù)的唯一標(biāo)識(shí)符。

LOCATION:設(shè)備描述文件的 URL,包含設(shè)備的詳細(xì)信息。

CACHE-CONTROL:設(shè)備信息的緩存時(shí)間,表示在多長(zhǎng)時(shí)間內(nèi)有效。

M-SEARCH請(qǐng)求報(bào)文實(shí)例:

M-SEARCH * HTTP/1.1
Host:239.255.255.250:1900
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1
Man:"ssdp:discover"
MX:3

字段解析:

M-SEARCH * HTTP/1.1:表明是一個(gè)搜索請(qǐng)求。

Host:多播地址和端口。

ST:搜索目標(biāo)類型,這里是IGD設(shè)備。

MX:最大響應(yīng)事件,設(shè)備需要在3秒內(nèi)返回響應(yīng)。

Man:搜索請(qǐng)求類型,固定。

M-SEARCH響應(yīng)報(bào)文實(shí)例:

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=60
DATE: Tue, 07 Jan 2025 06:43:49 GMT
EXT:
LOCATION: http://192.168.100.1:1900/igd.xml
SERVER: vxWorks/5.5 UPnP/1.0 TL-WR886N/6.0
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
USN: uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9::urn:schemas-upnp-org:device:InternetGatewayDevice:1

HTTP/1.1 200 OK:表示響應(yīng)成功。

CACHE-CONTROL:響應(yīng)有效時(shí)間為60秒。

DATE:響應(yīng)的時(shí)間戳。

EXT:保留字段,目前為空。

LOCATION:設(shè)備描述文件的URL。

SERVER:設(shè)備的操作系統(tǒng),UPnP版本和設(shè)備名稱。

ST:搜索目標(biāo)類型,和請(qǐng)求中的ST字段一致。

USN:唯一設(shè)備標(biāo)識(shí)符。

獲取設(shè)備標(biāo)識(shí)符

這一步會(huì)通過(guò)HTTP GET方式去請(qǐng)求xml文件,有關(guān)HTTP GET報(bào)文以及HTTP響應(yīng)報(bào)文這里不過(guò)多講解,有興趣的可以參考 HTTP Client章節(jié)。

請(qǐng)求示例:

GET /igd.xml HTTP/1.1
Accept: text/xml, application/xml
User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)
Host: 192.168.100.1:1900
Connection: Keep-Alive
Cache-Control: no-cache
Pragma: no-cache

響應(yīng)示例:

HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: 2580
Connection: close
Cache-control: no-cache




1
0


urn:schemas-upnp-org:device:InternetGatewayDevice:1
http://192.168.100.1:80 
Wireless N Router TL-WR886N
TP-LINK
http://www.tp-link.com.cn
TL-WR886N 6.0
TL-WR886N
6.0
uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9
123456789001


urn:schemas-upnp-org:service:Layer3Forwarding:1
urn:upnp-org:serviceId:L3Forwarding1
/l3f
/l3f
/l3f.xml




urn:schemas-upnp-org:device:WANDevice:1
WAN Device
TP-LINK
http://www.tp-link.com.cn
WAN Device
WAN Device
1.0

12345678900001
uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9
123456789001


urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
urn:upnp-org:serviceId:WANCommonInterfaceConfig
/ifc
/ifc
/ifc.xml




urn:schemas-upnp-org:device:WANConnectionDevice:1
WAN Connection Device
TP-LINK
http://www.tp-link.com.cn
WAN Connection Device
WAN Connection Device
1.0

12345678900001
uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9
123456789001


urn:schemas-upnp-org:service:WANIPConnection:1
urn:upnp-org:serviceId:WANIPConnection
/ipc
/ipc
/ipc.xml







訂閱IGD事件

通過(guò)HTTP SUBSCRIBE訂閱IGD事件,示例:

SUBSCRIBE /ipc HTTP/1.1
Host: 192.168.100.1:1900
USER-AGENT: Mozilla/4.0 (compatible; UPnP/1.1; Windows NT/5.1)
CALLBACK: 
NT: upnp:event
TIMEOUT: Second-1800

響應(yīng)示例:

HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: 0
Connection: close
Cache-control: no-cache
Server: vxWorks/5.5 UPnP/1.0 TL-WR886N/6.0
Timeout: Second-1800
SID: uuid:82-2150160019

添加映射端口報(bào)文

例如,我們想映射TCP協(xié)議的內(nèi)部端口8000到外部端口1000上,可以按照以下示例進(jìn)行HTTP請(qǐng)求:

POST /ipc HTTP/1.1
Content-Type: text/xml; charset="utf-8"
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)
Host: 192.168.100.1:1900
Content-Length: 1131
Connection: Keep-Alive
Cache-Control: no-cache
Pragma: no-cache








1000

TCP

8000

192.168.100.101
1
W5500_uPnPGetway
0


主要字段的描述如下:

m:AddPortMapping:添加端口映射

NewExternalPort:外部端口號(hào)

NewProtocol:協(xié)議類型

NewInternalPort:內(nèi)部端口號(hào)

NewInternalClient:內(nèi)部地址

響應(yīng)內(nèi)容:

HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: 289
Connection: close
Cache-control: no-cache
Server: vxWorks/5.5 UPnP/1.0 TL-WR886N/6.0


刪除端口映射報(bào)文

例如,我們想刪除上面映射的1000端口,可以按照以下示例進(jìn)行HTTP請(qǐng)求:

POST /ipc HTTP/1.1
Content-Type: text/xml; charset="utf-8"
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"
User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)
Host: 192.168.100.1:1900
Content-Length: 604
Connection: Keep-Alive
Cache-Control: no-cache
Pragma: no-cache





1000
TCP

主要字段的描述如下:

m:DeletePortMapping:刪除端口映射

NewExternalPort:外部端口號(hào)

NewProtocol:協(xié)議類型

NewRemoteHost:外部訪問(wèn)來(lái)源,可以為空

6實(shí)現(xiàn)過(guò)程

在這個(gè)例程中,我們實(shí)現(xiàn)了通過(guò)串口控制LED燈開(kāi)關(guān)、獲取和設(shè)置網(wǎng)絡(luò)地址信息、TCP和UDP回環(huán)數(shù)據(jù)測(cè)試以及UPnP添加映射端口和刪除映射端口的功能。

注意:測(cè)試實(shí)例需要W55MH32接入在支持UPnP端口轉(zhuǎn)發(fā)的路由器下。

步驟1:設(shè)置以太網(wǎng)緩存大小

static uint8_t  tx_size[_WIZCHIP_SOCK_NUM_] = {4, 4, 2, 1, 1, 1, 1, 2};
static uint8_t  rx_size[_WIZCHIP_SOCK_NUM_] = {4, 4, 2, 1, 1, 1, 1, 2};
/* socket rx and tx buff init */
wizchip_init(tx_size, rx_size);

在這里我們給socket0-7的收發(fā)緩存分別設(shè)置為4KB,4KB,2KB,1KB,1KB,1KB,1KB,2KB。

其中socket0用于UPnP協(xié)議處理,socket1用于TCP和UDP回環(huán)處理,socket2用于監(jiān)聽(tīng)I(yíng)GD事件。

步驟2:LED控制函數(shù)注冊(cè)

UserLED_Control_Init(set_user_led_status);

set_user_led_status()函數(shù)為控制LED的函數(shù),具體內(nèi)容如下:

/*void set_user_led_status(uint8_t val)
{
 if (val)
 {
     GPIO_SetBits(GPIOD, GPIO_Pin_14);
 }
 else
 {
     GPIO_ResetBits(GPIOD, GPIO_Pin_14);
 }
}

步驟3:搜索UPnP設(shè)備

do
{
   printf("Send SSDP.. rn");
}   while (SSDPProcess(SOCKET_ID) != 0); // SSDP Search discovery

/**< SSDP Header */
unsigned char SSDP[] = "
M-SEARCH * HTTP/1.1rn
Host:239.255.255.250:1900rn
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1rn
Man:"ssdp:discover"rn
MX:3rn
rn
";
/**
* @brief This function processes the SSDP message.
* @return 0: success, -1: reply packet timeout, 1: received SSDP parse error
*/
signed char SSDPProcess(SOCKET sockfd)
{
 char          ret_value     = 0;
 long          endTime       = 0;
 unsigned char mcast_addr[4] = {239, 255, 255, 250};
 // unsigned char_t_t mcast_mac[6] = {0x28, 0x2C, 0xB2, 0xE9, 0x42, 0xD6};
 unsigned char  recv_addr[4];
 unsigned short recv_port;
 // UDP Socket Open
 close(sockfd);
 socket(sockfd, Sn_MR_UDP, PORT_SSDP, 0); /*Initialize socket for socket 0*/
 while (getSn_SR(sockfd) != SOCK_UDP);
#ifdef UPNP_DEBUG
 printf("%srn", SSDP);
#endif
 // Send SSDP
 if (sendto(sockfd, SSDP, strlen((char *)SSDP), mcast_addr, 1900) <= 0)
     printf("SSDP Send error!!!!!!!rn");
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 endTime = my_time + 3;
 while (recvfrom(sockfd, (unsigned char *)recv_buffer, RECV_BUFFER_SIZE, recv_addr, &recv_port) <= 0 && my_time < endTime); // Check Receive Buffer
 if (my_time >= endTime)
 {                                                                                                                          // Check Timeout
     close(sockfd);
     return -1;
 }
 // UDP Socket Close
 close(sockfd);
#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
#endif
 // Parse SSDP Message
 if ((ret_value = parseSSDP(recv_buffer)) == 0)
     UPnP_Step = 1;
 return ret_value;
}

在這個(gè)函數(shù)中,主要是使用SSDP協(xié)議搜索IGD設(shè)備,發(fā)送報(bào)文和前面我們介紹的一致。

步驟4:獲取IGD設(shè)備描述

if (GetDescriptionProcess(SOCKET_ID) == 0) // GET IGD description
{
   printf("GetDescription Success!!rn");
}
else
{
   printf("GetDescription Fail!!rn");
}

/**
* @brief This function gets the description message from IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout, 1: received xml parse error
*/
signed char GetDescriptionProcess(
SOCKET sockfd /**< a socket number. */
)
{
char           ret_value = 0;
long           endTime   = 0;
unsigned long  ipaddr;
unsigned short port;
// Check UPnP Step
if (UPnP_Step < 1) return -2;
// Make HTTP GET Header
memset(send_buffer, '', SEND_BUFFER_SIZE);
MakeGETHeader(send_buffer);
#ifdef UPNP_DEBUG
printf("%srn", send_buffer);
#endif
ipaddr = inet_addr((unsigned char *)descIP);
ipaddr = swapl(ipaddr);
port   = ATOI(descPORT, 10);
// Connect to IGD(Internet Gateway Device)
close(sockfd);
socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
while (getSn_SR(sockfd) != SOCK_INIT)
{
 delay_ms(100);
}
if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
 printf("TCP Socket Error!!rn");
// Send Get Discription Message
while ((getSn_SR(sockfd) != SOCK_ESTABLISHED));
send(sockfd, (void *)send_buffer, strlen(send_buffer));
// Receive Reply
memset(recv_buffer, '', RECV_BUFFER_SIZE);
delay_ms(500);
endTime = my_time + 3;
while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer
if (my_time >= endTime)
{                                                                                      // Check Timeout
 close(sockfd);
 return -1;
}
// TCP Socket Close
close(sockfd);
#ifdef UPNP_DEBUG
printf("rnReceiveDatarn%srn", recv_buffer);
#endif
// Parse Discription Message
if ((ret_value = parseDescription(recv_buffer)) == 0) UPnP_Step = 2;
return ret_value;
}

請(qǐng)求報(bào)文通過(guò)MakeGETHeader()函數(shù)進(jìn)行組包,具體報(bào)文如下:

/**
* @brief   This function makes the HTTP GET header.
* @param   dest:Target string pointer
* @return  none
*/
void MakeGETHeader(char *dest)
{
   char local_port[6] = {''};
   strcat(dest, "GET ");
   strcat(dest, descLOCATION);
   strcat(dest, " HTTP/1.1rn");
   strcat(dest, "Accept: text/xml, application/xmlrn");
   strcat(dest, "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)rn");
   strcat(dest, "Host: ");
   strcat(dest, descIP);
   sprintf(local_port, ":%s", descPORT);
   strcat(dest, local_port);
   strcat(dest, "rnConnection: Keep-AlivernCache-Control: no-cachernPragma: no-cachernrn");
}

然后將接收到的內(nèi)容,通過(guò)parseDescription()函數(shù)進(jìn)行解析,如果設(shè)備描述中不支持WANIPConnection服務(wù),則說(shuō)明不支持端口映射,返回錯(cuò)誤。

parseDescription()函數(shù)內(nèi)容如下:

/**
* @brief This function parses the received description message from IGD(Internet Gateway Dev
* @return 0: success, 1: received xml parse error
*/
signed char parseDescription(
   const char *xml /**< string for parse */
)
{
   const char controlURL_[]  = "";
   const char eventSubURL_[] = "";
   char      *URL_start = 0, *URL_end = 0;
   if (parseHTTP(xml) != 0) return 1;
   //printf("rn%srn", xml);
   // Find Control URL("/etc/linuxigd/gateconnSCPD.ctl")
   if ((URL_start = strstr(xml, "urn:schemas-upnp-org:service:WANIPConnection:1")) == NULL) retur
   if ((URL_start = strstr(URL_start, controlURL_)) == NULL) return 1;
   if ((URL_end = strstr(URL_start, "")) == NULL) return 1;
   strncpy(controlURL, URL_start + strlen(controlURL_), URL_end - URL_start - strlen(controlURL_)
   // Find Eventing Subscription URL("/etc/linuxigd/gateconnSCPD.evt")
   if ((URL_start = strstr(xml, "urn:schemas-upnp-org:service:WANIPConnection:1")) == NULL) retur
   if ((URL_start = strstr(URL_start, eventSubURL_)) == NULL) return 1;
   if ((URL_end = strstr(URL_start, "")) == NULL) return 1;
   strncpy(eventSubURL, URL_start + strlen(eventSubURL_), URL_end - URL_start - strlen(eventSubUR
   return 0;
}

步驟5:訂閱IGD事件

if (SetEventing(SOCKET_ID) == 0) // Subscribes IGD event messages
{
   printf("SetEventing Success!!rn");
}
else
{
   printf("SetEventing Fail!!rn");
}

SetEventing()函數(shù)內(nèi)容如下:

/**
* @brief This function subscribes to the eventing message from IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout
*/
signed char SetEventing(
 SOCKET sockfd /**< a socket number. */
)
{
 long           endTime = 0;
 unsigned long  ipaddr;
 unsigned short port;
 // Check UPnP Step
 if (UPnP_Step < 2) return -2;
 // Make Subscription message
 memset(send_buffer, '', SEND_BUFFER_SIZE);
 MakeSubscribe(send_buffer, PORT_UPNP_EVENTING);
#ifdef UPNP_DEBUG
 printf("%srn", send_buffer);
#endif
 ipaddr = inet_addr((unsigned char *)descIP);
 ipaddr = swapl(ipaddr);
 port   = ATOI(descPORT, 10);
 // Connect to IGD(Internet Gateway Device)
 close(sockfd);
 socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
 while (getSn_SR(sockfd) != SOCK_INIT)
 {
     delay_ms(100);
 }
 if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
     printf("TCP Socket Error!!rn");
 // Send Get Discription Message
 while ((getSn_SR(sockfd) != SOCK_ESTABLISHED));
 send(sockfd, (void *)send_buffer, strlen(send_buffer));
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 delay_ms(500);
 endTime = my_time + 3;
 while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer
 if (my_time >= endTime)
 {                                                                                      // Check Timeout
     close(sockfd);
     return -1;
 }
 // TCP Socket Close
 close(sockfd);
#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
#endif
 return parseHTTP(recv_buffer);
}

請(qǐng)求報(bào)文通過(guò)MakeSubscribe()函數(shù)進(jìn)行組包,具體報(bào)文如下:

/**
* @brief   This function makes the Subscription message.
* @param   dest:Target string pointer
* @param   listen_port:Listen port
* @return  none
*/
void MakeSubscribe(char *dest, const unsigned int listen_port)
{
   char          local_port[6] = {''}, ipaddr[16] = {''};
   unsigned char ip[4];
   strcat(dest, "SUBSCRIBE ");
   strcat(dest, eventSubURL);
   strcat(dest, " HTTP/1.1rn");
   strcat(dest, "Host: ");
   strcat(dest, descIP);
   sprintf(local_port, ":%s", descPORT);
   strcat(dest, local_port);
   strcat(dest, "rnUSER-AGENT: Mozilla/4.0 (compatible; UPnP/1.1; Windows NT/5.1)rn");
   strcat(dest, "CALLBACK: ", listen_port);
   strcat(dest, local_port);
   strcat(dest, "rnNT: upnp:eventrnTIMEOUT: Second-1800rnrn");
}

最后,通過(guò)parseHTTP()函數(shù)解析HTTP響應(yīng)報(bào)文,判斷是否訂閱成功。

parseHTTP()函數(shù)如下:

/*-----String Parse Functions-----*/
/**
 * @brief This function parses the HTTP header.
 * @return 0: success, 1: received xml parse error
 */
signed char parseHTTP(
   const char *xml /**< string for parse */
)
{
   char *loc = 0;
   if (strstr(xml, "200 OK") != NULL)
       return 0;
   else
   {
       loc = strstr(xml, "rn");
       memset(content, '', CONT_BUFFER_SIZE);
       strncpy(content, xml, loc - xml);
       printf("rnHTTP Error:rn%srnrn", content);
       return 1;
   }
}

步驟6:執(zhí)行UPnP主程序

Main_Menu(SOCKET_ID, SOCKET_ID + 1, SOCKET_ID + 2, ethernet_buf, tcps_port, udps_port); // Main menu

/**
* @brief   Display/Manage a Menu on HyperTerminal Window
* @param   sn: use for SSDP; sn2: use for run tcp/udp loopback; sn3: use for listenes IGD event message
* @param   buf: use for tcp/udp loopback rx/tx buff; tcps_port: use for tcp loopback listen; udps_port: use 
for udp loopback receive
* @return  none
*/
void Main_Menu(uint8_t sn, uint8_t sn2, uint8_t sn3, uint8_t *buf, uint16_t tcps_port, uint16_t udps_port)
{
   static char           choice[3];
   static char           msg[256], ipaddr[12], protocol[4];
   static unsigned short ret, external_port, internal_port;
   static uint8_t        bTreat;
   static uint8_t        Sip[4];
   while (1)
   {
       /* Display Menu on HyperTerminal Window */
       bTreat = RESET;
       printf("rn====================== WIZnet Chip Control Point ===================rn");
       printf("This Application is basic example of UART interface withrn");
       printf("Windows Hyper Terminal. rn");
       printf("rn==========================================================rn");
       printf("                          APPLICATION MENU :rn");
       printf("rn==========================================================rnn");
       printf(" 1 - Set LED on rn");
       printf(" 2 - Set LED off rn");
       printf(" 3 - Show network settingrn");
       printf(" 4 - Set  network settingrn");
       printf(" 5 - Run TCP Loopbackrn");
       printf(" 6 - Run UDP Loopbackrn");
       printf(" 7 - UPnP PortForwarding: AddPortrn");
       printf(" 8 - UPnP PortForwarding: DeletePortrn");
       printf("Enter your choice : ");
       memset(choice, 0, sizeof(choice));
       scanf("%s", choice);
       printf("%crn", choice[0]);

在這里會(huì)執(zhí)行一個(gè)用戶選項(xiàng)菜單,選項(xiàng)1和2控制LED開(kāi)關(guān),選項(xiàng)3和4打印和設(shè)置網(wǎng)絡(luò)地址信息,選項(xiàng)5運(yùn)行一個(gè)TCP回環(huán)測(cè)試程序(回環(huán)測(cè)試程序可參考TCP Server章節(jié)),選項(xiàng)6運(yùn)行一個(gè)UDP回環(huán)測(cè)試程序(回環(huán)測(cè)試程序可參考UDP章節(jié))。選項(xiàng)7添加一個(gè)UPnP端口映射表,選項(xiàng)8刪除一個(gè)UPnP端口映射表。這里我們主要講解UPnP相關(guān)的選項(xiàng)7和選項(xiàng)8。

步驟7:添加一個(gè)UPnP端口映射表

代碼如下:

if (choice[0] == '7')
{
 bTreat = SET;
 printf("rnType a Protocol(TCP/UDP) : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 strncpy(protocol, msg, 3);
 protocol[3] = '';
 printf("rnType a External Port Number : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 external_port = ATOI(msg, 10);
 printf("rnType a Internal Port Number : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 internal_port = ATOI(msg, 10);
 if(strcmp(protocol,"tcp") || strcmp(protocol,"TCP"))
     tcps_port     = internal_port;
 else
     udps_port     = internal_port;
 close(sn2);
 // Try to Add Port Action
 getSIPR(Sip);
 sprintf(ipaddr, "%d.%d.%d.%d", Sip[0], Sip[1], Sip[2], Sip[3]);
 if ((ret = AddPortProcess(sn, protocol, external_port, ipaddr, internal_port, "W5500_uPnPGetway")) == 0)
     printf("AddPort Success!!rn");
 else
     printf("AddPort Error Code is %drn", ret);
}

在這里,我們需要外部輸入端口映射的協(xié)議類型(TCP或UDP),以及外部端口號(hào)和內(nèi)部端口號(hào)。輸入完成后,選項(xiàng)5或選項(xiàng)6的端口號(hào)會(huì)替換為輸入的內(nèi)部端口號(hào),然后通過(guò)AddPortProcess()函數(shù)執(zhí)行添加端口映射處理。AddPortProcess()函數(shù)內(nèi)容如下:

/**
* @brief This function processes the add port to IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout, 1: received xml parse error, other: UPnP error code
*/
signed short AddPortProcess(
SOCKET             sockfd,         /**< a socket number. */
const char        *protocol,       /**< a procotol name. "TCP" or "UDP" */
const unsigned int extertnal_port, /**< an external port number. */
const char        *internal_ip,    /**< an internal ip address. */
const unsigned int internal_port,  /**< an internal port number. */
const char        *description     /**< a description of this portforward. */
)
{
 short          len     = 0;
 long           endTime = 0;
 unsigned long  ipaddr;
 unsigned short port;
 // Check UPnP Step
 if (UPnP_Step < 2) return -2;
 // Make "Add Port" XML(SOAP)
 memset(content, '', CONT_BUFFER_SIZE);
 MakeSOAPAddControl(content, protocol, extertnal_port, internal_ip, internal_port, description);
 // Make HTTP POST Header
 memset(send_buffer, '', SEND_BUFFER_SIZE);
 len = strlen(content);
 MakePOSTHeader(send_buffer, len, ADD_PORT);
 strcat(send_buffer, content);
 //#ifdef UPNP_DEBUG
 printf("%srn", send_buffer);
 //#endif
 ipaddr = inet_addr((unsigned char *)descIP);
 ipaddr = swapl(ipaddr);
 port   = ATOI(descPORT, 10);
 // Connect to IGD(Internet Gateway Device)
 socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
 while (getSn_SR(sockfd) != SOCK_INIT);
 if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
     printf("TCP Socket Error!!rn");
 // Send "Delete Port" Message
 while (getSn_SR(sockfd) != SOCK_ESTABLISHED);
 send(sockfd, (void *)send_buffer, strlen(send_buffer));
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 delay_ms(500);
 endTime = my_time + 3;
 while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer
 if (my_time >= endTime)
 {                                                                                      // Check Timeout
     close(sockfd);
     return -1;
 }
 // TCP Socket Close
 close(sockfd);
 //#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
 //#endif
 // Parse Replied Message
 return parseAddPort(recv_buffer);
}

程序首先會(huì)通過(guò)MakeSOAPAddControl()函數(shù)組裝請(qǐng)求報(bào)文中的XML部分,具體內(nèi)容如下:

/**< SOAP header & tail */
const char soap_start[] =
   "
rn

";
const char soap_end[] =
   "
rn
";
/**< Delete Port Mapping */
const char DeletePortMapping_[] = "";
const char _DeletePortMapping[] = "";
/**< New Remote Host */
const char NewRemoteHost_[] = "";
const char _NewRemoteHost[] = "";
/**< New External Port */
const char NewExternalPort_[] = "";
const char _NewExternalPort[] = "";
/**< New Protocol */
const char NewProtocol_[] = "";
const char _NewProtocol[] = "";
/**< Add Port Mapping */
const char AddPortMapping_[] = "";
const char _AddPortMapping[] = "";
/**< New Internal Port */
const char NewInternalPort_[] = "";
const char _NewInternalPort[] = "";
/**< New Internal Client */
const char NewInternalClient_[] = "";
const char _NewInternalClient[] = "";
/**< New Enabled */
const char NewEnabled[]  = "1";
const char NewEnabled_[] = "";
const char _NewEnabled[] = "";
/**< New Port Mapping Description */
const char NewPortMappingDescription_[] = "";
const char _NewPortMappingDescription[] = "";
/**< New Lease Duration */
const char NewLeaseDuration[]  = "0";
const char NewLeaseDuration_[] = "";
const char _NewLeaseDuration[] = "";
/**
* @brief   This function makes the Add Port Control message in SOAP.
* @param   dest:Target string pointer
* @param   protocol:Protocol type
* @param   extertnal_port:External port
* @param   internal_ip:Internal IP address
* @param   internal_port:Internal port
* @param   description:Description
* @return  none
*/
void MakeSOAPAddControl(char *dest, const char *protocol, const unsigned int extertnal_port, const char * internal_ip, const unsigned int internal_port, const char *description)
{
   char local_port[6] = {''};
   strcat(dest, soap_start);
   strcat(dest, AddPortMapping_);
   strcat(dest, NewRemoteHost_);
   strcat(dest, _NewRemoteHost);
   strcat(dest, NewExternalPort_);
   sprintf(local_port, "%d", extertnal_port);
   strcat(dest, local_port);
   strcat(dest, _NewExternalPort);
   strcat(dest, NewProtocol_);
   strcat(dest, protocol);
   strcat(dest, _NewProtocol);
   strcat(dest, NewInternalPort_);
   sprintf(local_port, "%d", internal_port);
   strcat(dest, local_port);
   strcat(dest, _NewInternalPort);
   strcat(dest, NewInternalClient_);
   strcat(dest, internal_ip);
   strcat(dest, _NewInternalClient);
   strcat(dest, NewEnabled);
   strcat(dest, NewPortMappingDescription_);
   strcat(dest, description);
   strcat(dest, _NewPortMappingDescription);
   strcat(dest, NewLeaseDuration);
   strcat(dest, _AddPortMapping);
   strcat(dest, soap_end);
}

然后通過(guò)MakePOSTHeader()函數(shù)制作HTTP頭部?jī)?nèi)容,具體內(nèi)容如下:

  /**
 * @brief   This function makes the HTTP POST Header.
 * @param   dest:Target string pointer
 * @param   content_length: content length
 * @param   action: action type
 * @return  none
 */
 void MakePOSTHeader(char *dest, int content_length, int action)
 {
     char local_length[6] = {''}, local_port[6] = {''};
     sprintf(local_length, "%d", content_length);
     strcat(dest, "POST ");
     strcat(dest, controlURL);
     strcat(dest, " HTTP/1.1rn");
     strcat(dest, "Content-Type: text/xml; charset="utf-8"rn");
     strcat(dest, "SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#");
     switch (action)
     {
     case DELETE_PORT:
         strcat(dest, "DeletePortMapping"");
         break;
     case ADD_PORT:
         strcat(dest, "AddPortMapping"");
         break;
     }
     strcat(dest, "rnUser-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)rn");
     strcat(dest, "Host: ");
     strcat(dest, descIP);
     sprintf(local_port, ":%s", descPORT);
     strcat(dest, local_port);
     strcat(dest, "rnContent-Length: ");
     strcat(dest, local_length);
     strcat(dest, "rnConnection: Keep-AlivernCache-Control: no-cachernPragma: no-cachernrn");
 }

最后則是發(fā)送請(qǐng)求,然后通過(guò)parseAddPort()函數(shù)解析響應(yīng)內(nèi)容判斷是否添加端口映射成功。

signed short parseAddPort(
 const char *xml /**< string for parse */
)
{
 parseHTTP(xml);
 if (strstr(xml, "u:AddPortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"") == NULL)
 {
     return parseError(xml);
 }
 return 0;
}

步驟8:刪除一個(gè)UPnP端口映射表

if (choice[0] == '8')
{
 bTreat = SET;
 printf("rnType a Protocol(TCP/UDP) : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 //GetInputString(msg);
 strncpy(protocol, msg, 3);
 protocol[3] = '';
 printf("rnType a External Port Number : ");
 //   TCP_LISTEN_PORT=num;
 //   UDP_LISTEN_PORT=num;
 //   printf("%drn",TCP_LISTEN_PORT);
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 external_port = ATOI(msg, 10);
 // Try to Delete Port Action
 if ((ret = DeletePortProcess(sn, protocol, external_port)) == 0)
     printf("DeletePort Success!!rn");
 else
     printf("DeletePort Error Code is %drn", ret);
}
/* OTHERS CHOICE*/
if (bTreat == RESET)
{
 printf(" wrong choice  rn");
}

在這里,我們需要外部輸入刪除端口映射的協(xié)議類型(TCP或UDP),以及外部端口號(hào)。輸入完成后,通過(guò)DeletePortProcess()函數(shù)執(zhí)行添加端口映射處理。DeletePortProcess()函數(shù)內(nèi)容如下:

/**
* @brief This function processes the delete port to IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout, 1: received xml parse error, other: UPnP error code
*/
signed short DeletePortProcess(
 SOCKET             sockfd,        /**< a socket number. */
 const char        *protocol,      /**< a procotol name. "TCP" or "UDP" */
 const unsigned int extertnal_port /**< an external port number. */
)
{
 short          len     = 0;
 long           endTime = 0;
 unsigned long  ipaddr;
 unsigned short port;
 // Check UPnP Step
 if (UPnP_Step < 2) return -2;
 // Make "Delete Port" XML(SOAP)
 memset(content, '', CONT_BUFFER_SIZE);
 MakeSOAPDeleteControl(content, protocol, extertnal_port);
 // Make HTTP POST Header
 memset(send_buffer, '', SEND_BUFFER_SIZE);
 len = strlen(content);
 MakePOSTHeader(send_buffer, len, DELETE_PORT);
 strcat(send_buffer, content);
 //#ifdef UPNP_DEBUG
 printf("%srn", send_buffer);
 //#endif
 ipaddr = inet_addr((unsigned char *)descIP);
 ipaddr = swapl(ipaddr);
 port   = ATOI(descPORT, 10);
 // Connect to IGD(Internet Gateway Device)
 close(sockfd);
 socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
 while (getSn_SR(sockfd) != SOCK_INIT);
 if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
     printf("TCP Socket Error!!rn");
 // Send "Delete Port" Message
 while (getSn_SR(sockfd) != SOCK_ESTABLISHED);
 send(sockfd, (void *)send_buffer, strlen(send_buffer));
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 delay_ms(500);
 endTime = my_time + 3;
 while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer 
 if (my_time >= endTime)
 {                                                                                      // Check Timeout
     close(sockfd);
     return -1;
 }
 // TCP Socket Close
 close(sockfd);
 //#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
 //#endif
 // Parse Replied Message
 return parseDeletePort(recv_buffer);
}

首先會(huì)通過(guò)MakeSOAPDeleteControl()函數(shù)組裝請(qǐng)求報(bào)文中的XML部分,具體內(nèi)容如下:

/**
* @brief   This function makes the Delete Port Control message in SOAP.
* @param   dest:Target string pointer
* @param   protocol:Protocol type
* @param   extertnal_port:External port
* @return  none
*/
void MakeSOAPDeleteControl(char *dest, const char *protocol, const unsigned int extertnal_port)
{
    char local_port[6] = {''};
    strcat(dest, soap_start);
    strcat(dest, DeletePortMapping_);
    strcat(dest, NewRemoteHost_);
    strcat(dest, _NewRemoteHost);
    strcat(dest, NewExternalPort_);
    sprintf(local_port, "%d", extertnal_port);
    strcat(dest, local_port);
    strcat(dest, _NewExternalPort);
    strcat(dest, NewProtocol_);
    strcat(dest, protocol);
    strcat(dest, _NewProtocol);
    strcat(dest, _DeletePortMapping);
    strcat(dest, soap_end);
}

然后通過(guò)MakePOSTHeader()函數(shù)制作HTTP頭部?jī)?nèi)容,具體內(nèi)容如下:

 /**
* @brief   This function makes the HTTP POST Header.
* @param   dest:Target string pointer
* @param   content_length: content length
* @param   action: action type
* @return  none
*/
void MakePOSTHeader(char *dest, int content_length, int action)
{
   char local_length[6] = {''}, local_port[6] = {''};
   sprintf(local_length, "%d", content_length);
   strcat(dest, "POST ");
   strcat(dest, controlURL);
   strcat(dest, " HTTP/1.1rn");
   strcat(dest, "Content-Type: text/xml; charset="utf-8"rn");
   strcat(dest, "SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#");
   switch (action)
   {
   case DELETE_PORT:
       strcat(dest, "DeletePortMapping"");
       break;
   case ADD_PORT:
       strcat(dest, "AddPortMapping"");
       break;
   }
   strcat(dest, "rnUser-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)rn");
   strcat(dest, "Host: ");
   strcat(dest, descIP);
   sprintf(local_port, ":%s", descPORT);
   strcat(dest, local_port);
   strcat(dest, "rnContent-Length: ");
   strcat(dest, local_length);
   strcat(dest, "rnConnection: Keep-AlivernCache-Control: no-cachernPragma: no-cachernrn");
}

最后則是發(fā)送請(qǐng)求,然后通過(guò)parseDeletePort()函數(shù)解析響應(yīng)內(nèi)容判斷是否添加端口映射成功。

signed short parseDeletePort(
 const char *xml /**< string for parse */
)
{
 parseHTTP(xml);
 if (strstr(xml, "u:DeletePortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"") == NULL)
 {
     return parseError(xml);
 }
 return 0;
}

7運(yùn)行結(jié)果

燒錄例程運(yùn)行后,首先進(jìn)行了PHY鏈路檢測(cè),然后是通過(guò)DHCP獲取網(wǎng)絡(luò)地址并打印網(wǎng)絡(luò)地址信息:

wKgZO2iBk_qAJu0hAACGbFXSs4s753.png

接下來(lái)是搜索IGD設(shè)備,搜索成功后會(huì)進(jìn)行獲取設(shè)備描述以及設(shè)置訂閱IGD事件,全部成功后則進(jìn)入主菜單。

wKgZPGiBk_qAR8NXAAB7KK65PqM552.png

接著,我們輸入7,添加一個(gè)TCP協(xié)議的端口映射,外部端口為12345,內(nèi)部端口為8000。

wKgZPGiBlUGAJUKXAAB_qiS29yE458.png

打開(kāi)UPnP Wizard軟件,點(diǎn)擊刷新后可以看到我們添加的端口映射表。(UPnP Wizard下載鏈接:https://upnp-wizard.en.softonic.com/)

wKgZPGiBk_qAPl1rAABLZ3dYYI0094.png

然后我們輸入5,打開(kāi)TCP回環(huán)測(cè)試程序。

wKgZO2iBk_qAPyybAAB2Yd2UAUQ634.png

隨后,我們打開(kāi)一個(gè)網(wǎng)絡(luò)調(diào)試助手,例如SocketTester,選擇為T(mén)CP Client模式,服務(wù)器地址為外部IP地址也就是192.168.1.135,端口號(hào)為外部端口號(hào)12345,點(diǎn)擊”Connect”連接后,可以看到成功連接到內(nèi)部的W55MH32上了。UDP也是同樣進(jìn)行操作,這里不再演示。

wKgZPGiBk_uAWsuuAABgCNp5Vw4452.png

接著我們輸入Q退出回環(huán)測(cè)試程序,然后輸入8,將之前添加的TCP協(xié)議的12345外部端口刪除。在UPnP Wizard上點(diǎn)擊刷新,可以看到已經(jīng)成功刪除,再次執(zhí)行回環(huán)測(cè)試程序,已經(jīng)無(wú)法連接上內(nèi)部的W55MH32上。

wKgZPGiBk_qAHCnnAACLZa5NCuc107.pngwKgZO2iBk_qATGsqAADLCfGoIX0170.pngwKgZO2iBk_qAdqobAAAnyGquMak336.pngwKgZO2iBk_uAH-J3AACQC9YpHyc941.png

8總結(jié)

本文講解了如何在 W55MH32芯片上實(shí)現(xiàn) UPnP協(xié)議的端口轉(zhuǎn)發(fā)功能,通過(guò)實(shí)戰(zhàn)例程詳細(xì)展示了從設(shè)備搜索、獲取設(shè)備描述、訂閱事件到添加和刪除端口映射的完整流程,包括各步驟涉及的協(xié)議報(bào)文、函數(shù)實(shí)現(xiàn)和具體操作。文章還對(duì) UPnP協(xié)議的簡(jiǎn)介、特點(diǎn)、應(yīng)用場(chǎng)景進(jìn)行了分析,幫助讀者理解其在網(wǎng)絡(luò)設(shè)備互聯(lián)互通中的實(shí)際應(yīng)用價(jià)值。

下一篇文章將聚焦 TFTP協(xié)議,解析其核心原理及在文件傳輸中的應(yīng)用,同時(shí)講解如何在W55MH32上實(shí)現(xiàn) TFTP功能,敬請(qǐng)期待!

WIZnet是一家無(wú)晶圓廠半導(dǎo)體公司,成立于 1998年。產(chǎn)品包括互聯(lián)網(wǎng)處理器 iMCU?,它采用 TOE(TCP/IP卸載引擎)技術(shù),基于獨(dú)特的專利全硬連線 TCP/IP。iMCU?面向各種應(yīng)用中的嵌入式互聯(lián)網(wǎng)設(shè)備。

WIZnet在全球擁有 70多家分銷商,在香港、韓國(guó)、美國(guó)設(shè)有辦事處,提供技術(shù)支持和產(chǎn)品營(yíng)銷。

香港辦事處管理的區(qū)域包括:澳大利亞、印度、土耳其、亞洲(韓國(guó)和日本除外)。

審核編輯 黃宇

聲明:本文內(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ǎng)
    +關(guān)注

    關(guān)注

    41

    文章

    5876

    瀏覽量

    179035
  • 端口
    +關(guān)注

    關(guān)注

    4

    文章

    1092

    瀏覽量

    33666
  • UPnP
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    8600
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    第二十六章 W55MH32?上位機(jī)搜索和配置示例

    本文講解了如何在 W55MH32?芯片上實(shí)現(xiàn)上位機(jī)搜索和配置功能,通過(guò)實(shí)戰(zhàn)例程展示了使用開(kāi)源上位機(jī)配置工具 SmartConfigTool?搜索局域網(wǎng)中的 W55MH32?并進(jìn)行網(wǎng)絡(luò)地址配置的過(guò)程
    的頭像 發(fā)表于 07-24 16:13 ?468次閱讀
    第二十六章 <b class='flag-5'>W55MH32</b>?上位機(jī)搜索和配置<b class='flag-5'>示例</b>

    第二十三章 W55MH32 MQTT_OneNET示例

    本文講解了如何在 W55MH32?芯片上實(shí)現(xiàn) MQTT?協(xié)議并連接 OneNET?平臺(tái),通過(guò)實(shí)戰(zhàn)例程展示了從準(zhǔn)備工作、連接配置到消息訂閱、發(fā)布及接收處理的完整過(guò)程。文章詳細(xì)介紹了 MQTT?協(xié)議
    的頭像 發(fā)表于 07-24 14:59 ?548次閱讀
    第二<b class='flag-5'>十三章</b> <b class='flag-5'>W55MH32</b> MQTT_OneNET<b class='flag-5'>示例</b>

    第十八章 W55MH32 FTP_Server示例

    本文講解了如何在 W55MH32?芯片上實(shí)現(xiàn) FTP?協(xié)議的服務(wù)器模式,通過(guò)實(shí)戰(zhàn)例程展示了使用 W55MH32?作為 FTP?服務(wù)器與 PC?端進(jìn)行文件傳輸、目錄操作等功能的過(guò)程,涵蓋獲取網(wǎng)絡(luò)配置
    的頭像 發(fā)表于 07-24 11:55 ?358次閱讀
    <b class='flag-5'>第十</b>八章 <b class='flag-5'>W55MH32</b> FTP_Server<b class='flag-5'>示例</b>

    第十七章 W55MH32 ARP示例

    文講解了如何在 W55MH32?芯片上通過(guò) MAC RAW?模式實(shí)現(xiàn) ARP?協(xié)議,將 IP?地址解析為 MAC?地址,通過(guò)實(shí)戰(zhàn)例程展示了從發(fā)送 ARP?請(qǐng)求到接收并處理響應(yīng)的完整過(guò)程。文章詳細(xì)介紹
    的頭像 發(fā)表于 07-24 11:49 ?457次閱讀
    <b class='flag-5'>第十</b>七章 <b class='flag-5'>W55MH32</b> ARP<b class='flag-5'>示例</b>

    第十六章 W55MH32 PING示例

    本文講解了如何在 W55MH32?芯片上通過(guò) IPRAW?模式實(shí)現(xiàn) ICMP?協(xié)議中的 PING?命令,以進(jìn)行網(wǎng)絡(luò)連通性測(cè)試,通過(guò)實(shí)戰(zhàn)例程展示了從發(fā)送 PING?請(qǐng)求、接收并解析回復(fù)到統(tǒng)計(jì)結(jié)果的完整
    的頭像 發(fā)表于 07-24 11:41 ?398次閱讀
    <b class='flag-5'>第十</b>六章 <b class='flag-5'>W55MH32</b> PING<b class='flag-5'>示例</b>

    第十五章 W55MH32 SNMP示例

    本文講解了如何在 W55MH32?芯片上實(shí)現(xiàn) SNMP?功能,通過(guò)實(shí)戰(zhàn)例程展示了使用 MIB Browser?管理 W55MH32?的具體過(guò)程,涵蓋在 MIB Browser?中創(chuàng)建分支、添加葉子
    的頭像 發(fā)表于 07-24 10:43 ?536次閱讀
    <b class='flag-5'>第十</b>五章 <b class='flag-5'>W55MH32</b> SNMP<b class='flag-5'>示例</b>

    第十四章 W55MH32 TFTP示例

    本文講解了如何在 W55MH32?芯片上實(shí)現(xiàn) TFTP?協(xié)議,通過(guò)實(shí)戰(zhàn)例程詳細(xì)展示了使用 TFTP?客戶端模式從服務(wù)器獲取文本文件的過(guò)程,涵蓋 TFTP?初始化、發(fā)送讀請(qǐng)求、運(yùn)行協(xié)議并處理結(jié)果等核心
    的頭像 發(fā)表于 07-24 10:37 ?492次閱讀
    <b class='flag-5'>第十</b>四章 <b class='flag-5'>W55MH32</b> TFTP<b class='flag-5'>示例</b>

    第十二章 W55MH32 NetBIOS示例

    本文講解了如何在 W55MH32?芯片上實(shí)現(xiàn) NetBIOS?功能,通過(guò)實(shí)戰(zhàn)例程展示了利用 NetBIOS?進(jìn)行名稱 PING?測(cè)試的具體過(guò)程,包括 NetBIOS?功能的調(diào)用、請(qǐng)求處理、名稱解析
    的頭像 發(fā)表于 07-24 09:58 ?466次閱讀
    <b class='flag-5'>第十</b>二章 <b class='flag-5'>W55MH32</b> NetBIOS<b class='flag-5'>示例</b>

    第十一章 W55MH32 SMTP示例

    本文講解了如何在 W55MH32?芯片上實(shí)現(xiàn) SMTP?協(xié)議,通過(guò)實(shí)例詳細(xì)展示了在該芯片上使用 SMTP?協(xié)議發(fā)送電子郵件的實(shí)現(xiàn)流程,包括 SMTP?發(fā)送內(nèi)容初始化、使用 DNS?協(xié)議解析 SMTP
    的頭像 發(fā)表于 07-24 09:49 ?786次閱讀
    <b class='flag-5'>第十</b>一章 <b class='flag-5'>W55MH32</b> SMTP<b class='flag-5'>示例</b>

    第十W55MH32 SNTP示例

    本文講解了如何在W55MH32芯片上實(shí)現(xiàn)SNTP授時(shí)功能,通過(guò)實(shí)例詳細(xì)展示了從SNTP服務(wù)器同步時(shí)間的實(shí)現(xiàn)流程,包括時(shí)間請(qǐng)求、響應(yīng)解析和本地時(shí)間校準(zhǔn)等核心步驟。文章還對(duì)SNTP的應(yīng)用場(chǎng)景進(jìn)行了分析,幫助讀者理解其在時(shí)間同步中的實(shí)際應(yīng)用價(jià)值。
    的頭像 發(fā)表于 07-24 09:43 ?644次閱讀
    <b class='flag-5'>第十</b>章 <b class='flag-5'>W55MH32</b> SNTP<b class='flag-5'>示例</b>

    第九章 W55MH32 HTTP Server示例

    本文介紹了在 W55MH32?芯片上實(shí)現(xiàn) HTTP Server?功能,并通過(guò)瀏覽器修改其網(wǎng)絡(luò)地址信息的方法。闡述了 HTTP?協(xié)議的概念、特點(diǎn)、應(yīng)用場(chǎng)景、工作流程、請(qǐng)求方法、響應(yīng)內(nèi)容,以及 Web?頁(yè)面構(gòu)成和交互方式。展示了在W55MH32上實(shí)現(xiàn)的過(guò)程。
    的頭像 發(fā)表于 07-24 09:35 ?471次閱讀
    第九章 <b class='flag-5'>W55MH32</b> HTTP Server<b class='flag-5'>示例</b>

    第五章 W55MH32 UDP示例

    本文介紹了在 W55MH32?芯片上實(shí)現(xiàn) UDP?通信及數(shù)據(jù)回環(huán)測(cè)試的方法。闡述了 UDP?協(xié)議的概念、特點(diǎn)、應(yīng)用場(chǎng)景、報(bào)文傳輸流程和報(bào)文結(jié)構(gòu),展示了實(shí)現(xiàn)過(guò)程,借助網(wǎng)絡(luò)調(diào)試工具完成測(cè)試。
    的頭像 發(fā)表于 07-24 09:13 ?497次閱讀
    第五章 <b class='flag-5'>W55MH32</b> UDP<b class='flag-5'>示例</b>

    三章 W55MH32 TCP Client示例

    本文介紹在 W55MH32?芯片上實(shí)現(xiàn) TCP?客戶端模式進(jìn)行數(shù)據(jù)回環(huán)測(cè)試的方法。闡述 TCP?協(xié)議概念、特點(diǎn)、與 UDP?區(qū)別、應(yīng)用場(chǎng)景及相關(guān)機(jī)制。展示實(shí)現(xiàn)過(guò)程,包括開(kāi)啟 Keepalive?功能,在主循環(huán)運(yùn)行測(cè)試程序。燒錄例程后進(jìn)行 PHY?鏈路檢測(cè)、獲取網(wǎng)絡(luò)地址,再借助網(wǎng)絡(luò)調(diào)試工具測(cè)試。
    的頭像 發(fā)表于 07-24 09:06 ?600次閱讀
    第<b class='flag-5'>三章</b> <b class='flag-5'>W55MH32</b> TCP Client<b class='flag-5'>示例</b>

    第二章 W55MH32 DHCP示例

    本文介紹 DHCP?協(xié)議,包括其在 IP?網(wǎng)絡(luò)自動(dòng)分配參數(shù)的功能、便捷配置等特點(diǎn)、工作原理、報(bào)文格式和應(yīng)用場(chǎng)景。通過(guò) W55MH32?實(shí)戰(zhàn)例程展示動(dòng)態(tài)獲取網(wǎng)絡(luò)地址信息過(guò)程,含注冊(cè)定時(shí)器中斷、啟用模式和獲取信息等步驟,燒錄后可完成檢測(cè)與信息打印,PC?端能 PING?通設(shè)備。
    的頭像 發(fā)表于 07-24 09:02 ?489次閱讀
    第二章 <b class='flag-5'>W55MH32</b> DHCP<b class='flag-5'>示例</b>

    WIZnet W55MH32以太網(wǎng)單片機(jī)開(kāi)發(fā)教程 第十一章 通用定時(shí)器(上篇)

    本章介紹了W55MH32的通用定時(shí)器TIM2~TIM5,其由 16 位計(jì)數(shù)器等構(gòu)成,具輸入捕獲等功能,有多種計(jì)數(shù)模式及時(shí)鐘選擇。對(duì)例程進(jìn)行了講解并下載驗(yàn)證,TIM9~14功能類似,詳見(jiàn)《W55MH32參考手冊(cè)》。
    的頭像 發(fā)表于 05-28 10:12 ?753次閱讀
    WIZnet <b class='flag-5'>W55MH32</b>以太網(wǎng)單片機(jī)開(kāi)發(fā)教程 <b class='flag-5'>第十</b>一章 通用定時(shí)器(上篇)