<<返回上一页

UPnP协议演示


关键词:UPnP  W5500  WIZnet  W5500EVB  即插即用


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协议中的消息格式,按照格式要求去发送相应的数据包。

自动端口映射功能演示:
  1. 为了测试W5500 EVB自动端口映射功能,在执行DHCP、SSDP、获得描述和设置事件后,在串口上为用户提供了一个菜单页面,可以交互添加端口和删除端口,以及用来测试连接的loopback程序。 如果UPnP执行正确,会出现图1的串口输出,如果执行失败,请检查设备所在路由器是否开启了UPnP。最后程序会显示菜单页面,如图2。

  2. 图1:UPnP执行成功打印输出

    图2:程序完成初始化后的菜单界面.
  3. 按照菜单提示,我们首先添加一个TCP端口映射,外网端口为12345,内网端口为5000,添加成功后会提示AddPortSuccess。那么是否真的添加成功了呢,我们再来查看下是否有W5500EVB的映射,如图3,红色标识部分显示,端口映射添加成功。

  4. 图3:添加端口映射后路由器端口映射表
  5. 本篇实例并没有真正在外网测试,是在一个内网中再搭建一个内网,相对最内层的网络来说,外面的一层是“外网”,但是并不违背端口映射的原理。为了测试端口映射是否可用,我们按照菜单,执行TCP loopback程序,loopback中使用5000端口创建了一个TCP server, 前面我们已经将内网中的5000端口映射出去,首先检查下路由器在外网中的IP地址,如图4所示,路由器IP地址为192.168.10.128,可见路由器的网段与W5500EVB(IP地址是192.168.1.117)的网段不是一样的,这正是“外网”和内网的区别。我们在与路由器同一网段的PC (IP地址是192.168.10.116)上建立TCP client,连接到路由器的12345端口,并发送测试字符串“wiznet”,在接收区看到收到了loopback的回复。端口映射成功!如图5。

图4:查看路由器“外网”的IP地址

图5:loopback测试

例程下载:【UPnP】
编译环境:keil V5.11
硬件要求:W5500EVB