在Windows中使用C++进行UPnP端口转发
UPnP port forwarding with C++ in Windows
我正试图使用C++IUPnPNAT接口在windows下的P2P应用程序中实现自动端口转发,但我不能因为它总是返回NULL对象就让它工作。我不确定我的路由器是否支持UPnP,因为它在网络界面中没有显示任何选项,但如果我安装eMule或Skype,它们会立即打开端口并正常工作,所以问题一定出在我的代码或Microsoft界面中。eMule和Skype是如何做到的?Anobody能帮我吗?
我粘贴我的代码:
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;
}
非常感谢。
很抱歉,但您没有明确接收到的NULL指针的位置。
如果CoCreateInstance返回null,则表明有问题的类没有在相关机器上使用OLE/COM注册——Skype/eMule工作的事实无关紧要,因为它们可能使用的是应用程序中内置的库,而不是COM对象。
您应该确保COM对象已在使用它的系统上注册-在注册表中搜索UPnPNAT uuid。
如果你想让应用程序在多个系统上运行,那么你应该考虑直接链接到.lib,而不是使用COM连接到使用时可能在系统上注册或没有注册的对象。
很可能您没有打开网络发现。
我在连接到Guest或Public网络并进行调试时遇到了同样的问题。我发现调用get_StaticPortMappingCollection(..)
时,upnpnat.dll在运行时根本没有加载。如果未连接到专用网络,则可能由于安全限制而发生这种情况。可以在"控制面板"->"网络和共享中心"->"更改高级共享设置"中进行检查。
控制面板屏幕截图
在这种情况下,需要打开网络发现。对于专用网络来说,这并不重要。
相关文章:
- 正在折叠转发引用
- 将函数参数完美转发到函数指针:按值传递呢?
- 转发变量参数列表以模拟 std::thread
- 在按值调用 (c++) 中转发构造函数参数
- 存储稍后要转发的变量参数
- 如何在 C++ 中转发声明 std::set?
- C++使用默认模板参数键入别名和转发声明
- CNTK:->转发或 ->评估某些电脑上的崩溃,而不是其他电脑上的崩溃
- C++20理念:要求表达和完美转发
- 如何在模板中转发右值和左值引用
- 如何转发声明枚举?
- 使用函数指针转发声明作为 lamba 声明
- CAFFE转发网络在for循环中不起作用
- 如何将迭代器调用转发给类的私有成员?
- 转发复制的 std::tuple
- 完美的转发和构造函数
- 是否可以在不扣除的情况下将模板参数转发到 make_*?
- 通过基类接受方法转发派生 UniquePtr 的右值会移动引用而不是复制
- 如何将枚举类转发声明为模板化类的内部类?
- 在Windows中使用C++进行UPnP端口转发