使用UPnP来穿透NAT使内网接口对外网可见
在写完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.GetHostName();
Console.WriteLine("用户:" + name);
//从当前Host Name解析IP地址,筛选IPv4地址是本机的内网IP地址。
var ipv4 = Dns.GetHostEntry(name).AddressList.Where(i => i.AddressFamily ==AddressFamily.InterNetwork).FirstOrDefault();
Console.WriteLine("内网IP:" + ipv4);
接下来就是设置UPnP了,首先需要初始化UPnPNAT类型(他是一个接口,只不过通过CoClass特性把执行导向UPnPNATClass类型),接着通过UPnPNAT的StaticPortMappingCollection来添加或者删除UPnP绑定。注意在没有路由器或者路由器的UPnP不开启的情况下,StaticPortMappingCollection属性可能会返回null。
代码如下:
Console.WriteLine("设置UPnP");
//UPnP绑定信息
var eport = 8733;
var iport = 8733;
var description = "Mgen测试";
//创建COM类型
var upnpnat = new UPnPNAT();
var mappings = upnpnat.StaticPortMappingCollection;
//错误判断
if (mappings == null)
{
Console.WriteLine("没有检测到路由器,或者路由器不支持UPnP功能。");
return;
}
//添加之前的ipv4变量(内网IP),内部端口,和外部端口
mappings.Add(eport, "TCP", iport, ipv4.ToString(), true, description);
Console.WriteLine("外部端口:{0}", eport);
Console.WriteLine("内部端口:{0}", iport);
如果成功后,你应该可以在路由器的UPnP选项中看到这些数据:
设置好UPnP后,开始获取外网IP地址,可以通过这个网址(http://checkip.dyndns.org/)。此时只需要发送一个HTTP GET请求,然后把返回的HTML中的IP地址提取出来就可以了,我们用正则来提取IP地址。
代码如下:
//外网IP变量
string eip;
//正则
var regex = @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b";
using (var webclient = new WebClient())
{
var rawRes = webclient.DownloadString("http://checkip.dyndns.org/");
eip = Regex.Match(rawRes, regex).Value;
}
Console.WriteLine("外网IP:" + eip);
OK,这个时候(如果一切顺利的话),一切准备工作都做好了。我们有了:内网IP,内部端口,外网IP,外部端口。那么就可以做一个TCP连接做测试了。
直接建立一个TCP服务端,代表在NAT下的服务器,注意端口号要绑定到UPnP设置时的内部端口。
代码:
//在NAT下的服务器
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定内网IP和内部端口
socket.Bind(new IPEndPoint(ipv4, iport));
socket.Listen(1);
//在另一个线程中运行客户端Socket
Task.Run(() =>
{
Task.Delay(1000);
ClientSocket(eip, eport);
});
//成功连接
var client = socket.Accept();
//服务器向客户端发送信息
client.Send(Encoding.Unicode.GetBytes("=== 欢迎来到Mgen的服务器!===" + Environment.NewLine));
Console.ReadKey(false);
上面的ClientSocket方法就是客户端的Socket连接执行,注意TCP协议是不保留数据边界的,因此服务器在发送消息时,后面加了个换行符(Environment.NewLine),然后在客户端接受数据时,使用Socket –> NetworkStream –> StreamReader的嵌套组合,最后由StreamReader的ReadLine读取数据,这样确保会读到最后的换行符。
ClientSocket方法的执行代码:
//ip参数和port参数是公网的IP地址,和UPnP中的外部端口
static void ClientSocket(string ip, int port)
{
try
{
Console.WriteLine("建立客户端TCP连接");
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
using (var ns = new NetworkStream(socket))
using (var sr = new StreamReader(ns, Encoding.Unicode))
{
Console.WriteLine("收到来自服务器的回应:");
Console.WriteLine(sr.ReadLine());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
OK。
源代码下载
下载页面
注意:链接是微软SkyDrive页面,下载时请用浏览器直接下载,用某些下载工具可能无法下载
源代码环境:Microsoft Visual Studio Express 2012 for Windows Desktop
注意:源代码不包含引用的外部类库文件
本文版权归作者所有,欢迎以网址(链接)的方式转载,不欢迎复制文章内容的方式转载,其一是为了在搜索引擎中去掉重复文章内容,其二复制后的文章往往没有提供本博客的页面格式和链接,造成文章可读性很差。望有素质人自觉遵守上述建议。
如果一定要以复制文章内容的方式转载,必须在文章开头标明作者信息和原文章链接地址。否则保留追究法律责任的权利。
转载于:https://www.cnblogs.com/ppcompany/articles/2891215.html
使用UPnP来穿透NAT使内网接口对外网可见相关推荐
- 服务器内网与外网的四大区别?
服务器中的内网.外网是什么意思? 内网又称局域网(Local Area Network,LAN),是指在某一区域内由多台计算机以及网络设备构成的网络,比如校园网.政府网等,一般方圆几公里. 内网 即局 ...
- 内网和外网的区别+tcp协议ip协议详解
内网概念 即所说的局域网,比如学校的局域网,局域网内每台计算机的IP地址在本局域网内具有互异性,是不可重复的.但两个局域网内的内网IP可以有相同的. (连上WIFI,手机IP一般能在「设置」-「关于手 ...
- 什么是内网、外网?两者有何区别?
无论是在日常工作中还是生活中,很多小伙伴应该都接触过内网.外网,比如在学校的机房里就会使用内网,在部分企业办公室里上网也会使用内网,当然出于其他原因考虑,企业也会开放外网,只不过会对外网进行信息过滤. ...
- 负载均衡篇-LVS引出的网络知识:NAT、内网穿透及P2P
NAT 技术 NAT:网络地址转换.不知道大家有没有好奇过这个问题,即: 公司里面的电脑不能被外部网络直接访问,因为我们都属于内网,公司里各电脑同享一个公网IP. 但是,我们却能够主动连接外网,比如能 ...
- 【内网穿透服务器】使用FRP实现内网穿透,远程访问内网服务器
使用FRP实现内网穿透,远程访问内网服务器 frp 是一个高性能的反向代理应用,可以帮助您轻松地进行内网穿透,对外网提供服务,支持 tcp, http, https 等协议类型,并且 web 服务支持 ...
- 内网、外网、内网穿透、端口映射、IPV4、IPV6场景探讨
先附上各自概念,概念性的东西对于我们有一个大概的认识,那么实际使用与生活中又有哪些场景,来一一列举一些,了解下互联网的魅力! 一.内网 内网也叫局域网(Local Area Network,LAN), ...
- ***经验之教你穿透ADSL路由***内网
也许看烂了网上已有的常规******手段,对一些陈旧的***手法早已厌烦,近来我对ADSL MODEM的路由功能产生了浓厚的兴趣,经过一番努力,我终于找到了穿透ADSL路由***内网的方法,在这里和各 ...
- 内网穿透基础概念---内网外网
广域网和局域网 先上概念 广域网 广域网(英语:Wide Area Network,缩写为 WAN),又称外网.公网.是连接不同地区局域网或城域网计算机通信的远程网.通常跨接很大的物理范围,所覆盖的范 ...
- 浅谈网络地址转换(NAT)技术与内网、外网
前言 我们现在常使用的IP地址是IPv4地址,由四组0-255的十进制数字组成,中间以小数点分隔.Internet上的每一台主机或者路由器都至少有一个IP地址.IP地址(IPv4地址,下文IP地址默认 ...
最新文章
- 计算机网络实验思考题汇总
- Python 参考文档
- 51nod 1572 宝岛地图 (预处理四个方向的最大步数优化时间,时间复杂度O(n*m+k))
- python怎么设置代码执行时间_python 代码运行时间获取方式详解
- 如何在优雅地Spring 中实现消息的发送和消费 1
- 使PNG图片在IE浏览器实现透明效果代码
- python ndarray转binary_Python 实现Image和Ndarray互相转换
- java处理日期时间代码
- 阿里妈妈大规模在线分层实验实践
- Maven使用yuicompressor-maven-plugin打包压缩css、js文件
- PC微信机器人之实战分析微信加人call
- 值得关注的5款“企业级低代码开发平台”推荐
- mysql 约束1 100分_SQL SERVER CHECK语句,使用check约束限定成绩只能为0~100分
- 洛谷 P1359 租用游艇
- Execl中进行时间相加,对时间求和的公式:
- 头歌--Java入门 - 分支结构
- 免息贷款但有手续费的年化利率计算方法及Java实现;
- 培训演讲的小技巧,你知道多少?
- 部门换届推文文字_毕业季,换届忙
- YOLO系列网络训练数据准备工具—Yolo_mark