【问题标题】:UPnP port forwarding with C++ in Windows在 Windows 中使用 C++ 进行 UPnP 端口转发
【发布时间】:2012-01-06 00:20:29
【问题描述】:

我正在尝试使用C++ IUPnPNAT接口在windows下的P2P应用程序中实现自动端口转发,但我不能让它工作,因为它总是返回一个NULL对象。我不确定我的路由器是否支持 UPnP,因为它在 Web 界面中没有显示任何选项,但是如果我安装 eMule 或 Skype,它们会立即打开端口并且工作正常,所以问题一定出在我的代码中或在微软界面中。 eMule 和 Skype 是如何做到的?有人可以帮我吗?

我粘贴我的代码:

WORD abre_puerto() {
WORD puerto, i; 
wchar_t buf_port[12], puerto_s[6]; 
char nombre[256], ip[16]; 
wchar_t ipw[16], descripcion[100];
struct addrinfo *resultado = NULL; 
struct addrinfo *ptr = NULL; 
struct addrinfo hints; 
struct sockaddr_in *sockaddr_ipv4;
IUPnPNAT *nat; 
IStaticPortMappingCollection *coleccion; 
IStaticPortMapping *mapeado; 
BSTR protocolo, ipb;

swprintf(buf_port, sizeof(buf_port), L"%d", time(NULL));
swprintf(puerto_s, sizeof(puerto_s), L"151%c%c", buf_port[wcslen(buf_port) - 2], buf_port[wcslen(buf_port) - 1]);
puerto = _wtoi(puerto_s);

if(gethostname(nombre, sizeof(nombre)) == SOCKET_ERROR) {return 0;}
ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP;
if(getaddrinfo(nombre, NULL, &hints, &resultado) != 0) {return 0;}

sockaddr_ipv4 = (struct sockaddr_in *)resultado->ai_addr;
strcpy(ip, inet_ntoa(sockaddr_ipv4->sin_addr));
MultiByteToWideChar(CP_UTF8, 0, ip, -1, ipw, sizeof(ipw));
ipb = SysAllocString(ipw);

nat = NULL; coleccion = NULL; mapeado = NULL;

if(CoInitialize(NULL) != S_OK) {return 0;}

if(CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&nat) != S_OK) {return 0;}
else if(nat == NULL) {return 0;}

if(nat->get_StaticPortMappingCollection(&coleccion) != S_OK) {return 0;}
else if(coleccion == NULL) {return 0;} //fails here: coleccion is allways NULL!

protocolo = SysAllocString(L"TCP");
wcscpy(descripcion, TEXT("PROOF"));

for(i = 0; i < 250; i++) {
if(coleccion->get_Item(puerto, protocolo, &mapeado) != S_OK || mapeado == NULL) {break;}
puerto++; mapeado->Release(); mapeado = NULL;
}
if(i == 250) {return 0;}
if(coleccion->Add(puerto, protocolo, puerto, ipb, TRUE, descripcion, &mapeado) != S_OK) {return 0;}
else if(mapeado == NULL) {return 0;}
nat->Release(); coleccion->Release(); mapeado->Release();
CoUninitialize();

return puerto;
}

非常感谢。

【问题讨论】:

    标签: c++ upnp


    【解决方案1】:

    抱歉,但您没有明确说明收到的 NULL 指针的位置。

    如果 CoCreateInstance 返回 null,则表明相关类未在相关机器上使用 OLE/COM 注册 - 事实上 Skype/eMule 工作无关紧要,因为它们可能使用已构建的库进入应用程序,而不是 COM 对象。

    您应该确保 COM 对象已在使用它的系统上注册 - 在注册表中搜索 UPnPNAT uuid。

    如果您想让应用程序在多个系统上工作,那么您应该考虑直接链接到 .lib,而不是使用 COM 连接到在系统上注册或未注册的对象正在使用中。

    【讨论】:

    • 看起来 UPnp 框架是 Windows 上的可选安装 - 所以很可能它没有安装在您正在测试的系统上。
    • 对不起,我忘了在我的问题中提到 NULL 对象来自哪里,但是如果您阅读我在代码中留下的注释,它是在调用 IUPnPNAT 接口的 get_StaticPortMappingCollection 方法时, NULL 对象是“IStaticPortMappingCollection *coleccion”,该方法不会失败,返回 S_OK,它只是始终为空的对象。 CoCreateInstance 返回 S_OK 并正确填充 IUPnPNAT 接口。该机器使用Windows 7,并且在同一个路由器的同一个盒子中,eMule 每次启动时都会工作并打开端口(可能使用MiniUPnPc 库?)。
    【解决方案2】:

    很可能您没有打开网络发现。

    我在连接到 Guest 或 Public 网络并进行一些调试时遇到了同样的问题,我发现 upnpnat.dll 根本没有加载调用 get_StaticPortMappingCollection(..) 时的运行时。如果您连接到私有网络,则可能会因安全限制而发生这种情况。可以在控制面板 -> 网络和共享中心 -> 更改高级共享设置中检查。

    Control Panel screen shot

    在这种情况下需要开启网络发现。对于私有网络,这并不重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-03
      • 2013-01-07
      • 2017-04-23
      • 2012-04-02
      • 1970-01-01
      • 1970-01-01
      • 2015-02-09
      • 2014-08-18
      相关资源
      最近更新 更多