現今網上p2p的 udp nat穿透 文章 多如牛毛, p2p tcp nat的文章寥寥無幾 ,up主研究了幾天 終於有所收獲,特來向大家分享,請大家多多支持!
1、首先你要有台外網服務器 或者 電信的運營商 支持轉發的路由器(具體過程不多說,請自行百度)
2、一台能上網的電腦(內網裡面的電腦 不然沒有意義)
核心代碼就是:
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
作用就是讓已經連接的端口可以再次監聽 從而實現tcp nat 的目的
原理圖:

外網服務器端代碼 (ps:up主窮 買不起服務器 只能用公司的路由器轉發 ,請見諒!):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace TcpNatTestS
{
class Program
{
public static IPAddress GetLocalIP()
{
try
{
string HostName = Dns.GetHostName(); //得到主機名
IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
for (int i = 0; i < IpEntry.AddressList.Length; i++)
{
//從IP地址列表中篩選出IPv4類型的IP地址
//AddressFamily.InterNetwork表示此IP為IPv4,
//AddressFamily.InterNetworkV6表示此地址為IPv6類型
if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
return IpEntry.AddressList[i];
}
}
return IPAddress.Any;
}
catch (Exception ex)
{
return IPAddress.Any;
}
}
static void Main(string[] args)
{
TcpListener tcp = new TcpListener(new IPEndPoint(GetLocalIP(), 8085));
tcp.Start();
new Thread(e =>
{
while (true)
{
var lianjie = tcp.AcceptTcpClient();
//new TcpClient().Connect((IPEndPoint)lianjie.Client.RemoteEndPoint);
lianjie.Client.Send(UnicodeEncoding.Unicode.GetBytes("你的外網ip是:" + lianjie.Client.RemoteEndPoint));
Console.WriteLine("內網服務器: 本地端口:" + lianjie.Client.LocalEndPoint + "遠程端口:" + lianjie.Client.RemoteEndPoint);
}
}).Start();
Console.ReadKey();
}
}
}
內網客戶端(你需要自己填寫外網服務器ip):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace TcpNatTestA
{
class Program
{
public static IPAddress GetLocalIP()
{
try
{
string HostName = Dns.GetHostName(); //得到主機名
IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
for (int i = 0; i < IpEntry.AddressList.Length; i++)
{
//從IP地址列表中篩選出IPv4類型的IP地址
//AddressFamily.InterNetwork表示此IP為IPv4,
//AddressFamily.InterNetworkV6表示此地址為IPv6類型
if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
return IpEntry.AddressList[i];
}
}
return IPAddress.Any;
}
catch (Exception ex)
{
return IPAddress.Any;
}
}
static void Main(string[] args)
{
new Thread(e =>
{
TcpClient clinet = new TcpClient();
clinet.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
var bendi = new IPEndPoint(GetLocalIP(), 7896);
clinet.Client.Bind(bendi);
clinet.Connect(new IPEndPoint(IPAddress.Parse("請填寫你的服務器ip"), 8085));
TcpListener tcp = new TcpListener(bendi);
tcp.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
tcp.Start();
new Thread(() =>
{
while (true)
{
var jiqi= tcp.AcceptTcpClient();
Console.WriteLine("內網客戶機: 本地端點:" + bendi + " 遠程端點:" + jiqi.Client.RemoteEndPoint);
}
}).Start();
clinet.Client.Send(UnicodeEncoding.Unicode.GetBytes("呵呵呵呵"));
byte[] hh = new byte[500];
var weishu = clinet.Client.Receive(hh);
byte[] temp = new byte[weishu];
Array.Copy(hh, temp, weishu);
//Console.WriteLine("遠程端口:"+clinet.Client.RemoteEndPoint);
Console.WriteLine(UnicodeEncoding.Unicode.GetString(temp));
}).Start();
Console.ReadKey();
}
}
}
有問題歡迎大家聯系我