热度 31
2012-6-25 10:54
1656 次阅读|
0 个评论
大家好,前面我们为大家分享了如何实现W5200E01-M3中的UPnP(通用即插即用) 端口转发(一),今天继续为大家分享第二部分,希望对大家有帮助~ 第一部分请参考: http://forum.eet-cn.com/BLOG_ARTICLE_12795.HTM 3. 端口转发和W5200 工作流程 这篇应用笔记主要介绍了在 W5200 单片机中通过 UPnP 执行端口发送的过程。在此过程中, W5200 是 IGD 的控制指针,它能够编辑端口的发送功能。同时, W5200 单片机也是 LAN 客户端, IGD 则来执行端口转发。这样我们可以总结为, W5200 单片机控制指针能够向 IGD 发送命令执行端口发送函数。所有的指令都基于 IGD 标准,这些标准由因特网网关工作委员会定义,而委员会又是由 UPnP 建立的。基本上,端口发送包括两个步骤:一是添加端口映射,另一个是删除端口映射。除此以外,在添加和删除端口映射的过程中,有一些异常需要 W5200 单片机去处理,例如: 1.映射入口的冲突 : 端口映射入口指定的冲突在之前就已经由另一个客户端分配。 2. 更多的异常可以在 IGD 服务模板中找到 。 这篇应用手册将会介绍 W5200 如何添加以及删除端口映射。下面的图形也解释了 W5200UPnP 端口转发的过程。 注意: 更多关于Step0寻址 的信息,请参阅“如何用 W5200 实现 DHCP 通信”。 图 5. W5200 的 UPnP 端口发送过程 阶段1 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 获取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 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); } 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); } 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 提交事件 (可选) 为了能够提交事件,首先W5200单片机通过IGD的IP地址、端口号和事件提交URL来完成GENA信息,然后将GENA信息发送给IGD。 SUBSCRIBE eventSubURL HTTP/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; } 如果您有什么疑问,请直接留言或登录WIZnet官方网站:http://www.wiznettechnology.cn/ 或者来电:86-10-84539974(转166),QQ:2377211388, 邮箱:wiznetbj@wiznettechnology.com 联系人:Jerry ,谢谢!