如何實現W5200E01-M3中的UPnP(通用即插即用) 端口轉發(二)

大家好,前面我們為大家分享了如何實現W5200E01-M3中的UPnP(通用即插即用)端口轉發(一),這篇繼續為大家分享第二部分,希望對大家有幫助~

第一部分請參考:http://blog.iwiznet.cn/?p=1075

3. 端口轉發和W5200

工作流程

這篇應用筆記主要介紹了在W5200單片機中通過UPnP執行端口發送的過程。在此過程中,

W5200是IGD的控制指針,它能夠編輯端口的發送功能。同時,W5200單片機也是LAN客戶端,IGD則來執行端口轉發。這樣我們可以總結為,W5200單片機控制指針能夠向IGD發送命令執行端口發送函數。所有的指令都基於IGD標準,這些標準由因特網網關工作委員會定義,而委員會又是由UPnP建立的。基本上,端口發送包括兩個步驟:一是添加端口映射,另一個是刪除端口映射。除此以外,在添加和刪除端口映射的過程中,有一些異常需要W5200單片機去處理,例如:

1.映射入口的衝突:端口映射入口指定的衝突在之前就已經由另一個客戶端分配。

2.更多的異常可以在IGD服務模板中找到[5]。

這篇應用手冊將會介紹W5200如何添加以及刪除端口映射。下面的圖形也解釋了W5200UPnP端口轉發的過程。

注意: 更多關於<Step0>尋址的信息,請參閱“如何用W5200實現DHCP通信”。

 

圖5. W5200的UPnP端口發送過程

1.   階段1

A. SSDP

為了能夠搜索在相同子網中的IGD,W5200必須使用UDP多播地址發送SSDP M-SEARCH信息。

注意:SSDP利用多播地址、通用socket方式來發送數據。例如:

1)在實際的多播過程中,W5200單片機必須採取下面的方式打開socket:

socket(sock_id, Sn_MR_UDP, MULTICAST_PORT, Sn_MR_MULTI);

2)在SSDP中,W5200單片機仍然可以創建通用socket:

socket(sock_id, Sn_MR_UDP, MULTICAST_PORT,0)

在這篇應用手冊中,所有和描述相關的多播都屬於2)中的情況。

SSDP響應能夠使W5200獲知IGD的IP地址、端口號以及所有的描述URL。

M-SEARCH  * HTTP/1.1\r\n

Host:239.255.255.250:1900\r\n

ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n

Man:”ssdp:discover”\r\n

MX:3\r\n

\r\n

下面的源代碼在SSDPProcess()函數執行:

{

      初始化一個多播的socket(UDP,目的IP是239.255.255.250,目的端口是1900,目的MAC是0x01:0x00:0x5E:0x7F:0xFF:0xFA)

      //發送SSDP

      sendto(sockfd, SSDP, strlen(SSDP),  mcast_addr, 1900);

      //接收回復

      while

      {

           if(overtime){

                 close a multicasting socket

                 return -1;

           }else if(receive buffer is not  empty){

                 receive the SSDP response  from IGD to recv_buffer

           }

      }

      Close a multicasting socket

      // 解析SSDP信息

      return parseSSDP(recv_buffer);

}

2.   階段2

A.   獲取IGD服務的描述

利用IGD的IP地址,端口號和Description URL描述來完成HTTP GET Header,然後將其發送給IGD。

當IGD接收到HTTP GET Header後,IGD將會讓W5200單片機獲知它的描述。

描述過程將會使W5200獲知它的Control URL以及Eventing Subscription URL。

GET  destURL HTTP/1.1\r\n

Accept:  text/xml, application/xml\r\n

User-Agent:  Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n”);

Host:  destIP:destPORT\r\n

Connection:  Keep-Alive\r\n

Cache-Control:  no-cache\r\n

Pragma:  no-cache\r\n

\r\n

下面的源代碼是由GetDescriptionProcess()函數來執行的。

{

      //構造HTTP  GET Header

      MakeGETHeader(send_buffer);

      Initialize a unicasting socket

      //連接到IGD(Internet Gateway Device)

      connect(sockfd, ipaddr of IGD, port of  IGD);

      wait while connecting to IGD

      //發送Get  Discription Message

      send(sockfd, send_buffer,  strlen(send_buffer), FALSE);

      //接收回復

      while

      {

           if(overtime){

                 close a unicasting socket

                 return -1;

           }else if(receive buffer is not  empty){

                 receive the SSDP response  from IGD to recv_buffer

           }

      }

      Close a unicasting socket

      //解析Discription  Message

      return parseDescription(recv_buffer);

}

3.   階段3

A. Case 1:添加端口控制

利用IGD的IP地址、端口號以及控制URL來完成XML,然後通過HTTP POST method-based

SOAP執行AddPortMapping操作。

下面的源代碼是由AddPortProcess()函數執行的。.

{

      //構造”Add  Port” XML(SOAP)

      MakeSOAPAddControl(content, protocol,  extertnal_port, internal_ip, internal_port, description);

      //構造HTTP  POST Header

      MakePOSTHeader(send_buffer,  strlen(content), ADD_PORT);

      strcat(send_buffer, content);

      Initialize a unicasting socket

      //連接到IGD(Internet Gateway Device)

      connect(sockfd, ipaddr of IGD, port of  IGD);

      wait while connecting to IGD

      //發送”Add  Port”信息

      send(sockfd, send_buffer,  strlen(send_buffer), FALSE);

      // 接收回復

      while

      {

           if(overtime){

                 close a unicasting socket

                 return -1;

           }else if(receive buffer is not  empty){

                 receive the SSDP response  from IGD to recv_buffer

           }

      }

      close a unicasting socket

      //解析回複信息

      return parseAddPort(recv_buffer);

}

B.    Case 2: 刪除端口控制

利用IGD的IP地址、端口號以及控制URL來完成XML,然後通過HTTP POST method-based

SOAP執行DeletePortMapping操作。

下面的源代碼是在DeletePortProcess()函數中執行的。

{

      //構造”Delete  Port” XML(SOAP)

      MakeSOAPDeleteControl(content, protocol,  extertnal_port);

      //構造HTTP  POST Header

      MakePOSTHeader(send_buffer,  strlen(content), DELETE_PORT);

      strcat(send_buffer, content);

      Initialize a unicasting socket

      //連接到(Internet  Gateway Device)

      connect(sockfd, ipaddr of IGD, port of  IGD);

      wait while connecting to IGD

      // 發送”Delete  Port”信息

      send(sockfd, send_buffer,  strlen(send_buffer), FALSE);

      // 接收回復

      while

      {

           if(overtime){

                 close a unicasting socket

                 return -1;

           }else if(receive buffer is not  empty){

                 receive the SSDP response  from IGD to recv_buffer

           }

      }

      close a unicasting socket

      //解析回複信息

      return parseDeletePort(recv_buffer);

}

C.    Case 1和Case 2測試

為了確認UPnP端口轉發能否正常工作,用戶可以在遠程PC機上運行TCP客戶端,然後將其連接到W5200(TCP服務器)單片機。用戶可以參考第五章節“學習如何檢驗AddPortMapping和DeletePortMapping的使用舉例”。

下面的源代碼是在tcp_test()函數中執行的。

{

      switch (getSn_SR(sockfd))

      {

           case SOCK_ESTABLISHED:/* 如果連接建立*/

                 if(receive buffer is not  empty){

                       recv(sockfd,  recv_buffer, len);

                 }

           break;

           case SOCK_CLOSE_WAIT:/*如果客戶端請求關閉 */

                 if (receive buffer is not  empty)

                 {

                       recv(sockfd,  recv_buffer, len);

                 }

                 disconnect(sockfd);

           break;

           case SOCK_CLOSED:/*如果socket關閉 */

                 reinitialize a TCP socket

                 listen

           break;

      }

}

4.   階段4

A.   提交事件 (可選)

為了能夠提交事件,首先W5200單片機通過IGD的IP地址、端口號和事件提交URL來完成GENA信息,然後將GENA信息發送給IGD。

SUBSCRIBE  eventSubURLHTTP/1.1\r\n

Host:  destIP:destPORT\r\n

USER-AGENT:  Mozilla/4.0 (compatible; UPnP/1.1; Windows NT/5.1)\r\n

CALLBACK:  <http://myIP:listen_port/>\r\n

NT:  upnp:event\r\n

TIMEOUT:  Second-1800\r\n

\r\n

下面的源代碼是在SetEventing()函數中執行的。

{

      // 構造Subscription  message

      MakeSubscribe(send_buffer, listen_port);

      Initialize a unicasting socket

      // Connect to IGD(Internet Gateway  Device)

      connect(sockfd, ipaddr of IGD, port of  IGD);

      wait while connecting to IGD

      // 發送Subscription  Message

      send(sockfd, send_buffer,  strlen(send_buffer), FALSE);

      //接收回復

      while

      {

           if(overtime){

                 close a unicasting socket

                 return -1;

           }else if(receive buffer is not  empty){

                 receive the SSDP response  from IGD to recv_buffer

           }

      }

      close a unicasting socket

      return 0;

}

B.   接收事件

為了能夠從IGD接收事件,W5200單片機創建一個TCP服務器端口,這個端口負責監聽事件。當W5200單片機接收到事件信息時,parseEventing()函數將會使信息變成可讀的,並且通過串口進行顯示。

下面的源代碼是在eventing_listener()函數中執行的。

{

      switch (getSn_SR(sockfd))

      {

           case SOCK_ESTABLISHED:/* 如果連接建立*/

                 if(receive buffer is not empty){

                       recv(sockfd,  recv_buffer, len);

                       send(sockfd, HTTP_OK,  strlen(HTTP_OK), FALSE);

                       // Parse Replied  Message

                       parseEventing(recv_buffer);

                 }

           break;

           case SOCK_CLOSE_WAIT:/*如果客戶端請求關閉 */

                 if (receive buffer is not  empty)

                 {

                       recv(sockfd,  recv_buffer, len);

                 }

                 disconnect(sockfd);

           break;

           case SOCK_CLOSED:/* 如果socket關閉 */

                 reinitialize a TCP socket

                 listen

           break;

      }

}

更多有關W5200的視頻和博文請看這裡:

W5200相關視頻http://blog.iwiznet.cn/?page_id=484

使用高速SPI以太網控制芯片W5200登錄Telnet服務器(三)http://blog.iwiznet.cn/?p=412

高速SPI以太網控制芯片——W5200 http://blog.iwiznet.cn/?p=366

WIZnet的開源硬件(OSHW)芯片的角色是什麼?

WIZnet的開源硬件(OSHW)芯片的角色是什麼?