通过UPNP实现内网端口映射
0
最近在写一个下载软件,HTTP和FTP实现起来比较简单,通过JDK自带的包就能实现。但是P2P的下载实现起来确实比较麻烦,要实现的东西比较多。
由于P2P需要本机的端口被外网访问,所以这里就需要用到这个端口映射的技术。
首先我们需要使用M-SEARCH
来扫描内网里面的设备和服务。
M-SEARCH
这个是SSDP
协议里面的一个请求方法,使用的是HTTPU
协议,其实和HTTP
协议很像,只不过是用的UDP
实现的一个多播请求,只有请求头,没有body
:
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MX: 2
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
MAN: "ssdp:discover"
上面的请求头除了MX
都是固定的。
然后就能收到一个响应,响应头里面有个location
,访问这个地址获取一个XML
。
然后找到<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
这个服务,访问对应的SCPDURL
,可以得到类似WebService里面的接口描述。
这个里面就有很多接口,这里只用到一下几个:
- 添加端口映射:AddPortMapping
- 删除端口映射:DeletePortMapping
- 获取外网IP地址:GetExternalIPAddress
- 获取端口映射:GetSpecificPortMappingEntry
参数在XML描述里面已经有了,很简单易懂。
方法请求时,直接使用HTTP POST
请求即可,请求body
就是XML
,请求头添加SOAPAction
。
例如获取外网IP地址,使用POST请求:
添加请求头:
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"
请求XML:
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetExternalIPAddress xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"/>
</s:Body>
</s:Envelope>
其他的请求基本上修改请求头后面的方法名称,还有s:Body
里面的请求参数即可。
参考代码:https://gitee.com/acgist/snail/tree/master/snail/src/main/java/com/acgist/snail/net/upnp
测试代码:
https://gitee.com/acgist/snail/blob/master/snail/src/test/java/com/acgist/snail/net/upnp/UpnpClientTest.java
https://gitee.com/acgist/snail/blob/master/snail/src/test/java/com/acgist/snail/context/UpnpContextTest.java