ESP8266 UPnP端口转发 - 物联网
是否可以在使用ESP8266的路由器上使用UPNP协议进行自动端口转发?ESP8266 UPnP端口转发 - 物联网
即使我离家出走,我也需要访问我的ESP8266模块。 目前我已在我的路由器设置中手动配置端口转发。
但是在未来,为了让我的项目成为一个商业产品,它需要能够自动进行端口转发,因为这对于普通用户来说是一个障碍。
在互联网上,我发现了一些在ESP8266上谈论UPNP的东西,但它不是关于端口转发。
非常感谢您提前!
我不明白为什么不。 UPnP实现了多个配置文件,您感兴趣的配置文件名为IGD (Internet Gateway Device),大多数家庭路由器都实现了允许本地网络(例如Skype,uTorrent等)上的客户端应用程序映射路由器NAT上的端口。
UPnP通过IP multicast工作,发现并宣布在地址239.255.255.250
上实施UPnP服务的设备。对此类通告感兴趣的设备订阅这个多播组并在端口1900
上侦听。实际上,UPnP本身并不提供发现机制,但依靠名为SSDP (Simple Service Discovery Protocol)的协议来发现本地网络上的主机。
所需要的只是绑定到上述地址和端口的UDP套接字,以便在您的家庭多播组上订阅和发布消息。您需要使用SSDP的实现来发现您的路由器,一旦发现了您的路由器,就可以使用包裹在SOAP信封上的UPnP发送命令。
Posix C中有很多UPnP IGD配置文件的实现,您可以重复使用并连接到ESP 8266(例如MiniUPnP,gupnp-igd)。
你可以看看我的图书馆,我只是做了该: https://github.com/ofekp/TinyUPnP
我对包内的IOT装置(LED灯)的一个例子,我不能将链接附加由于低信誉。
你可以看看示例代码。全部为ESP8266制造。 使用起来非常简单,只需调用addPortMapping和要打开的端口即可,正如示例中所示。 因为UPnP是基于租约的协议,所以您必须每36000 (LEASE_DURATION)
秒完成一次。
声明:本
unsigned long lastUpdateTime = 0;
TinyUPnP *tinyUPnP = new TinyUPnP(-1); // -1 means blocking, preferably, use a timeout value (ms)
设置:
if (tinyUPnP->addPortMapping(WiFi.localIP(), LISTEN_PORT, RULE_PROTOCOL_TCP, LEASE_DURATION, FRIENDLY_NAME)) {
lastUpdateTime = millis();
}
循环:
// update UPnP port mapping rule if needed
if ((millis() - lastUpdateTime) > (long) (0.8D * (double) (LEASE_DURATION * 1000.0))) {
Serial.print("UPnP rule is about to be revoked, renewing lease");
if (tinyUPnP->addPortMapping(WiFi.localIP(), LISTEN_PORT, RULE_PROTOCOL_TCP, LEASE_DURATION, FRIENDLY_NAME)) {
lastUpdateTime = millis();
}
}
我只能用我的d-link路由器检查它。
感兴趣的人在库中是如何工作的:
- 它发送M_SEARCH消息UPnP的UDP多播地址。
- 网关路由器将回应一条消息,其中包含一个名为
Location
的HTTP标头。 -
Location
是一个指向包含IGD(互联网网关设备)API的XML文件的链接,以便创建所需的呼叫,从而将新的端口映射添加到网关路由器。 - 在XML中描述的其中一项服务是
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>
,这是图书馆正在查找的内容。 - 该服务将包含一个
eventSubURL
标记,它是链接到您的路由器的IGD API的标记。 (基本URL也显示在标记URLBase
下的同一文件中) - 使用基本URL和WANPPPConnection链接,您可以向将添加UPnP规则的路由器发出HTTP查询。
- 作为一个附注,XML中描述的服务还包含一个
SCPDURL
标记,该标记是另一个XML的链接,描述了可用于服务及其参数的命令。这个包跳过了这个阶段,因为我认为这个查询对于很多路由器来说是相似的,但这可能不是这种情况,所以这是由你来检查的。 - 从这个阶段开始,软件包将使用HTTP查询向路由器发出服务命令。实际的查询可以看到代码很清楚,但有兴趣的人士:
页眉:
"POST " + <link to service command from XML> + " HTTP/1.1"
"Content-Type: text/xml; charset=\"utf-8\""
"SOAPAction: \"urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping\""
"Content-Length: " + body.length()
身体:
"<?xml version=\"1.0\"?>\r\n"
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
"<s:Body>\r\n"
"<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\r\n"
" <NewRemoteHost></NewRemoteHost>\r\n"
" <NewExternalPort>" + String(rulePort) + "</NewExternalPort>\r\n"
" <NewProtocol>" + ruleProtocol + "</NewProtocol>\r\n"
" <NewInternalPort>" + String(rulePort) + "</NewInternalPort>\r\n"
" <NewInternalClient>" + ipAddressToString(ruleIP) + "</NewInternalClient>\r\n"
" <NewEnabled>1</NewEnabled>\r\n"
" <NewPortMappingDescription>" + ruleFriendlyName + "</NewPortMappingDescription>\r\n"
" <NewLeaseDuration>" + String(ruleLeaseDuration) + "</NewLeaseDuration>\r\n"
"</u:AddPortMapping>\r\n"
"</s:Body>\r\n"
"</s:Envelope>\r\n";
我希望这有助于。