1、关于地址映射的穿透,实测UDP可以,TCP不可以。
从道理上来说,TCP作为有连接传输,在nat设备上应该是匹配了对端ip地址的;但更有可能,出口设备做了阻止外到内tcp连接的acl。UDP应该没有,所以任意ip可以向nat设备的对应端口发包,内网机器都能收到。
2、关于套接字复用
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
之后,确实可以对套接字s0使用正在使用的节点。但最好对重复使用的两个套接字都指定复用,否则还是会报错。(实作指定后一个可以,后来必须两个都指定。懒得找原因了)
附:本次TCP测试的三个程序代码:
a、服务端程序(.net core)
using System; using System.Net; using System.Net.Sockets; using System.IO; namespace ConsoleApp1 { class Program { static void Main(string[] args) { TcpListener listener = new TcpListener(IPAddress.Any, 9000); listener.Start(); var tcp = listener.AcceptTcpClient(); var sr = new StreamReader(tcp.GetStream()); string msg = ""; do { msg = sr.ReadLine(); Console.WriteLine($"{tcp.Client.RemoteEndPoint.ToString()}:{msg}"); } while (msg.ToLower()!="exit"); } } }
b、客户端程序,模拟内网用户,希望能穿透nat(.net core)
using System; using System.Net; using System.Net.Sockets; using System.IO; namespace App2 { class Program { static void Main(string[] args) { IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("自己的ip"), 9100); string msg=""; Socket s0 = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); s0.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); s0.Bind(ipe); s0.Connect(IPAddress.Parse("服务器ip"), 9000); var sw = new StreamWriter(new NetworkStream(s0)); // try { do { msg = Console.ReadLine(); sw.WriteLine(msg); sw.Flush(); } while (msg.ToLower()!="next"); } catch (Exception e) { Console.WriteLine($"写入失败:{e.Message}"); } Console.WriteLine("开始进入监听状态:"); Socket s = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp),s1; s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); s.Bind(ipe); s.Listen(20); s1 = s.Accept(); Console.WriteLine($"{s1.RemoteEndPoint.ToString()}已连接..."); var sr = new StreamReader(new NetworkStream(s1)); do { msg = sr.ReadLine(); Console.WriteLine($"{s1.RemoteEndPoint.ToString()}:{msg}"); msg = Console.ReadLine(); sw.WriteLine(msg); sw.Flush(); } while (msg.ToLower() != "exit"); } } }
c、另一个用户(.net framework)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net; using System.Net.Sockets; using System.IO; namespace App4 { class Program { static void Main(string[] args) { IPEndPoint ipe = new IPEndPoint(IPAddress.Any, 9200); string ip; int port; Console.WriteLine("请输入ip:"); ip = Console.ReadLine(); Console.WriteLine("请输入port:"); port = int.Parse(Console.ReadLine()); TcpClient tcp = new TcpClient(ipe); Console.WriteLine("输入任意键开始连接"); Console.ReadKey(); tcp.Connect(IPAddress.Parse(ip), port); var sw = new StreamWriter(tcp.GetStream()); string msg = ""; try { do { sw.WriteLine(Console.ReadLine()); sw.Flush(); } while (msg.ToLower() != "next"); } catch (Exception e) { Console.WriteLine($"写入失败:{e.Message}"); } } } }
实验过程:1启动,2启动,任意输入验证,输入next进入监听模式,3启动,输入1读出的ip和port
实验结果:2、3程序在本机:通过;2、3程序分别部署:3中显示目标计算机积极拒绝。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现