UPNP是微软定义的一个网络标准,大概是通过网络发送xml定义的数据实现控制网络上的设备等。感兴趣的可以自己到 UPnP™ Forum (http://www.upnp.org/)上下载资料,或者网上搜索一下了。
端口映射: 就是把内网机器的网络端口映射的外部网络的相应端口上,这很多路由器都支持这样的功能。这样人家访问外网ip相应端口时就可以跳转到内网来。很多网络下载 工具都实现这样的功能的,这样人家从外部就可以连接到你内部的机器,便于网络操作,像BitComet,PPstream,迅雷等。
我就是看到BitComet的这个功能才学着自己也做一个。因为路由器实现了UPNP的标准接口了,就可以通过upnp来做到编程来做端口映射,免得去找网管了^_^,就是找了他也不一定给你弄呵呵。
参考资料:
微软的UPnP APIs:http://msdn2.microsoft.com/en-us/library/aa382303.aspx
UPNP标准 设备Internet Gateway Device (IGD) V 1.0 http://www.upnp.org/standardizeddcps/igd.asp
另外如果想实现UPNP的服务端的,好像也有Intel的 UPNP SDK库可以用的。网上也有人很多人写了自动端口映射的程序,我就找到一个使用 socket和 自己处理xml文件的方法实现的。不过我觉得微软有API了用起来也很简单的,不用自己处理那些东西,所以就把msdn上面的实例代码copy一个过来 了,改了一下,还真可以。
大概流程就是:
InternetGatewayDevice -》WANDevice-》WANConnectionDevice
-》WANIPConnection或者 WANPPPConnection,WANIPConnection的 DeletePortMapping,AddPortMapping,GetGenericPortMappingEntry,GetExternalIPAddress 等方法就可以用来做端口映射了。
这是两个实例图:
注意在windows的防火墙里面开放 “UPNP框架” 相应的端口UPNP才能正常工作,因为它是通过网络来进行的。
程序的运行效果如图,我在自己的机器上可以正常显示端口映射,并且进行删除,添加等操作了。发现有的人用PPsteam,迅雷啊等,那些程序都添加了端口映射了。不知道我把他们的映射删了,我的网络会不会快点,哈哈
一些关键代码:
case IDC_START:
{
BSTR bstrTypeURI = NULL;
bstrTypeURI = SysAllocString(L"urn:schemas-upnp-org:device:InternetGatewayDevice:1");
IUPnPDevice * internetGatewayDevice =NULL;
if (FindUPnPDevice(bstrTypeURI,&internetGatewayDevice))
{
char devicename[256];
if (GetDeviceFriendlyName(internetGatewayDevice,devicename))
{
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, devicename, 1);
}
SysFreeString(bstrTypeURI);
bstrTypeURI = SysAllocString(L"urn:schemas-upnp-org:device:WANDevice:1");
IUPnPDevice * wanDevice =NULL;
if (GetChildDevice(internetGatewayDevice ,bstrTypeURI ,&wanDevice))
{
if (GetDeviceFriendlyName(wanDevice,devicename))
{
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, devicename, 2);
}
SysFreeString(bstrTypeURI);
bstrTypeURI = SysAllocString(L"urn:schemas-upnp-org:device:WANConnectionDevice:1");
IUPnPDevice * wanConnectionDevice =NULL;
if (GetChildDevice(wanDevice ,bstrTypeURI ,&wanConnectionDevice))
{
if (GetDeviceFriendlyName(wanConnectionDevice,devicename))
{
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, devicename, 3);
}
SysFreeString(bstrTypeURI);
bstrTypeURI = SysAllocString(L"urn:schemas-upnp-org:service:WANIPConnection:1");
IUPnPService * WANIPConnection =NULL;
if (GetService(wanConnectionDevice ,bstrTypeURI ,&WANIPConnection))
{
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, "WANIPConnection", 4);
}
if (WANIPConnection)
{
char IPAddress[64];
if (InvokeGetExternalIPAddress(WANIPConnection,IPAddress))
{
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, IPAddress, 4);
}
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, "RemoteHost,ExternalPort
,PortMappingProtocol,InternalPort,InternalClient,PortMappingEnabled
,PortMappingDescription,PortMappingLeaseDuration", 4);
char PortMapping[256];
int i =0;
while(InvokeGetGenericPortMappingEntry(WANIPConnection,i,PortMapping))
{
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, PortMapping, 4);
i ++;
}
WANIPConnection->Release();
}
SysFreeString(bstrTypeURI);
bstrTypeURI = SysAllocString(L"urn:schemas-upnp-org:service:WANPPPConnection:1");
IUPnPService * WANPPPConnection =NULL;
if (GetService(wanConnectionDevice ,bstrTypeURI ,&WANPPPConnection))
{
hwndTreeView = GetDlgItem(hDlg,IDC_TREE1);
AddItemToTree(hwndTreeView, "WANPPPConnection", 4);
}
if (WANPPPConnection)
{
WANPPPConnection->Release();
}
}
if (wanConnectionDevice)
{
wanConnectionDevice->Release();
}
}
if (wanDevice)
{
wanDevice->Release();
}
}
SysFreeString(bstrTypeURI);
if (internetGatewayDevice)
{
internetGatewayDevice->Release();
}
}
break;
============
不过不知道为什么,端口映射成功后还是没办法从外面连接到里面的ip
(widebright) |