第一部分请参考:
http://wiznet2012.blogspot.kr/2012/06/w5200e01-m3upnp.html
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:添加端口控制
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; 
      } 
} | 


 
没有评论:
发表评论