UPnP网络的基本组件分为服务、设备和控制点三个部分,在本实例中,W5500EVB板是IGD的控制点,它能够控制IGD执行端口映射服务。这样,外网中的PC可以与内网中的W5500EVB板建立连接。在经过寻址、发现和获得描述后,使用端口映射服务包括两个步骤� 一是添加端口映射,另一个是删除端口映射�
W5500EVB板UPnP端口映射的过程分为两个步骤:步骤1:使用DHCP协议自动获取IP;
步骤2:使用SSDP发现设备,
为了能够搜索在相同子网中的IGD,W5500必须使用UDP多播地址发送SSDP M-SEARCH信息;控制点入网后会组播如下的格式数据包:
M-SEARCH * HTTP/1.1 Host:239.255.255.250:1900 ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1 Man:"ssdp:discover" MX:3
Host:这里必须使用IANA(InternetAssigned Numbers Authority)为SSDP预留的组播地址�239.255.255.250:1900�
ST:SearchTarger,表示搜索的节点类型,这里要找到IGD设备
Man:必须是“ssdp:discover”�
Mx�1�5之间的一个值,表示最大的等待应答的秒数�
设备收到SSDP M-SEARCH信息后会回复如下格式的数据包�
HTTP/1.1 200 OK CACHE-CONTROL: max-age=600 DATE: Sat, 07 Jan 2006 21:11:02 GMT EXT: LOCATION: http://192.168.1.1:1900/igd.xml SERVER: Wireless N Router WR842N, UPnP/1.0 ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1 USN: uuid:upnp-InternetGatewayDevice-282cb2e942d6::urn:schemas-upnp-org:device:InternetGatewayDevice:1
Cache-control:max-age的数值表明设备将在这段时间后失效,因此,设备应当在失效前,重发这样的消息�
Location:设备描述文件的URL。通过Location信息,我们能够获得IGD的IP地址和端口号�
Usn:Unique Service Name,是一个设备实例的标识符�
下面的伪代码在SSDPProcess()函数中实�
/*SSDP Header定义 */ constchar SSDP[]="\ 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\ "; signedcharSSDPProcess(SOCKET sockfd)//使用sockfd建立UDP完成SSDP流程 { //初始化一个UDP socket socket(sockfd,Sn_MR_UDP,PORT_SSDP,0); //发送SSDP搜索� sendto(sockfd,(const uint8*)SSDP,strlen(SSDP); //接收网络中设备回� recvfrom(sockfd,(uint8*)recv_buffer,RECV_BUFFER_SIZE,recv_addr,&recv_port); //完成SSDP流程,关闭socket close(sockfd); //解析SSDP数据� if((ret_value=parseSSDP(recv_buffer))==0) UPnP_Step=1;//收到指定设备数据包,进入下一步骤 returnret_value; }
步骤3�:获取IGD服务的描�
利用IGD的IP地址和端口号生成HTTP GET Header,然后将其发送给IGD。当IGD接收到HTTP GET Header后,IGD将会让W5500EVB获知它的描述。描述过程将会使W5500EVB获知它的Control URL以及eventSubURL URL�
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.1.1:1900 Connection: Keep-Alive Cache-Control: no-cache Pragma: no-cache
在IGD回复的信息中,我们可以看到设备描述和服务描述,WANIPConnection对应端口映射服务,可以看到IGD设备有该项服务。在WANIPConnection服务描述中可以得到Control URL和eventSubURL URL� 一个用来控制,一个用来订阅�
下面的伪代码是由GetDescriptionProcess()函数来执行的�
signedcharGetDescriptionProcess(SOCKET sockfd) { //检查SSDP是否成功完成 if(UPnP_Step<1) return-2; //生成HTTP GET Header MakeGETHeader(send_buffer); //descIP和descPORT在SSDP过程中获得,转化格式 ipaddr=inet_addr((uint8*)descIP); ipaddr=swapl(ipaddr); port= ATOI(descPORT,10); //初始化一个TCP socket socket(sockfd,Sn_MR_TCP,PORT_UPNP,Sn_MR_ND); //连接IGD(Internet Gateway Device) connect(sockfd,(uint8*)&ipaddr, port); //发送Get Description Message send(sockfd,(void*)send_buffer,strlen(send_buffer)); //接收IGDDescription recv(sockfd,(void*)recv_buffer, RECV_BUFFER_SIZE); //描述过程结束,断开连接 close(sockfd); //解析Description Message if((ret_value=parseDescription(recv_buffer))==0) UPnP_Step=2;//收到指定设备数据包,进入下一步骤 returnret_value; }
步骤:4:添加端口控�
利用IGD的IP地址、端口号以及控制URL来完成XML,然后通过HTTP POST method-basedSOAP执行AddPortMapping操作�
在SOAP描述中可以看到ExternalPort、Protocol、InternalPort以及控制点IP地址等信息�
下面的伪代码是由AddPortProcess()函数执行的�
if(UPnP_Step<2)return-2; // Make "Add Port" XML(SOAP) MakeSOAPAddControl(content, protocol,extertnal_port,internal_ip,internal_port, description); // Make HTTP POST Header len=strlen(content); MakePOSTHeader(send_buffer,len, ADD_PORT); strcat(send_buffer, content); //descIP和descPORT在SSDP过程中获得,转化格式 ipaddr=inet_addr((uint8*)descIP); ipaddr=swapl(ipaddr); port= ATOI(descPORT,10); //初始化一个TCP socket socket(sockfd,Sn_MR_TCP,PORT_UPNP,Sn_MR_ND); //连接IGD(Internet Gateway Device) connect(sockfd,(uint8*)&ipaddr, port); //发送SOAP信息 send(sockfd,(void*)send_buffer,strlen(send_buffer)); //接收应答 recv(sockfd,(void*)recv_buffer, RECV_BUFFER_SIZE); //控制过程结束,断开连接 close(sockfd); //检查控制是否成� returnparseAddPort(recv_buffer); }
在添加端口映射成功后,就可以在外网访问内网中指定IP地址和端口了,如果添加了TCP端口映射,可以建立连接并发送数据测试�
步骤5:删除端口控制。SOAP执行DeletePortMapping操作。删除操作只需要ExternalPort和Protocol两个参数即可。在收到“urn:schemas-upnp-org:service:WANIPConnection:1”后,表明端口映射删除成功�
下面的源代码是在DeletePortProcess()函数中执行的�
shortlen=0; longendTime=0; uint32ipaddr; uint16 port; //检查是否完成描述过� if(UPnP_Step<2) return-2; //Make "Delete Port" XML(SOAP) MakeSOAPDeleteControl(content, protocol,extertnal_port); // Make HTTP POST Header len=strlen(content); MakePOSTHeader(send_buffer,len, DELETE_PORT); strcat(send_buffer, content); //descIP和descPORT在SSDP过程中获得,转化格式 ipaddr=inet_addr((uint8*)descIP); ipaddr=swapl(ipaddr); port= ATOI(descPORT,10); //初始化一个TCP socket socket(sockfd,Sn_MR_TCP,PORT_UPNP,Sn_MR_ND); //连接IGD(Internet Gateway Device) connect(sockfd,(uint8*)&ipaddr, port); //发送SOAP信息 send(sockfd,(void*)send_buffer,strlen(send_buffer)); //接收应答 recv(sockfd,(void*)recv_buffer, RECV_BUFFER_SIZE); //控制过程结束,断开连接 close(sockfd); //检查控制是否成� returnparseDeletePort(recv_buffer); }
从以上描述可以看出,W5500执行收发的函数都很简单,重点是了解UPnP的实现过程,以及每个步骤中,UPnP协议中的消息格式,按照格式要求去发送相应的数据包�
自动端口映射功能演示: