在写完Object 672后,软件的一个致命问题暴露出来,如果服务器和客户端都在内网环境下,即双方都通过NAT来接触外网,那么此时客户端是无法直接和服务器交流的。
解决方案可以是:
1:把服务器部署在不存在NAT的公网环境下。
2:使用常见的NAT穿透方法比如UDP打洞,或者STUN协议,但是这些方法都需要另一个已知的部署在公网环境下的服务器。
3:就是这篇文章主要讨论的方案,即不需要部署任何公网环境下的服务器,通过路由器支持的UPnP协议来把内网的接口绑定到公网接口上。
UPnP的一大优势就是不会像UDP打洞那样,内网接口不需要先向外部接口发送UDP包来把绑定的公网接口告诉NAT,而且对于对称NAT,UDP打洞是无效的。而UPnP一旦设置成功后,内网接口完全以绑定的公网接口暴露在公网中。
演示程序的运行是这样的:
具体过程:
1. 输出用户Host Name和内网IP地址。
2. 通过UPnP把内网IP地址,内部端口号绑定到一个外部端口号上。
3. 通过HTTP从外部网站获取公网IP地址。
4. 在内网中创建TCP Socket服务器。
5. 建立另一个TCP Socket客户端,然后尝试连接上面获取的公网IP和UPnP绑定的外部端口。
6. 如果一切没有问题的话,此时会成功连接到服务器,并收到回应!
在.NET环境下使用Windows的UPnP组件需要现在工程中引用:NATUPnP 1.0 Type Library,这是一个COM类库。
下面开始逐句分析源代码,源代码均拟用户已加入下列命名空间:
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions; //提取IP时的正则
using System.Threading.Tasks; //Task
using System.IO; //读取服务器信息用到StreamReader
using NATUPNPLib; //Windows UPnP COM组件
首先输出本机(也就是内网接口信息),这个很简单了:
//获取Host Name
var name = Dns</