`

穿越net 打洞原理___java实现(原创)

阅读更多

我的上一篇日志是说明打洞原理http://smallbee.iteye.com/blog/1029835

 

下面来说说如何用java实现穿越。  感谢(你是我的谁?  83289331)提供代码

 

服务器端:

 

public class UDPServer extends UDPAgent {
	public static void main(String[] args) throws Exception {
		//开启2008服务器端口,接收客户端udp请求,同时也接收用户命令
		new UDPServer(2008).start();
	}
	public UDPServer(int port) {
		super(port);
	}
}

 

客户端:

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

public class UDPClient extends UDPAgent {
	public static void main(String[] args) throws Exception {
		new UDPClient("127.0.0.1", 2008, -1).start();
	}
	private SocketAddress server;
	public UDPClient(String host, int port, int localPort) {
		super(localPort);
		this.server = new InetSocketAddress(host, port);
	}
	public void start() throws Exception {
		println("start");
		init(); //构造客户端的 DatagramSocket
		register(); //向服务器发送字符串:register " + getLocalAddress() + " " + ds.getLocalPort()
		new Thread(this).start();//往自己输入的一个ip port发送东西 
		receive(); //循环接收服务器发来请求 打印出来
	}
	public void onReceive(DatagramPacket rec) {
		try {
			report(rec);
			if (rec.getSocketAddress().equals(server)) {
				doCommand(new String(rec.getData(), rec.getOffset(), rec
						.getLength()));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void report(DatagramPacket rec) throws Exception {
		String s = rec.getSocketAddress()
				+ new String(rec.getData(), rec.getOffset(), rec.getLength());
		byte[] buf = s.getBytes();
		ds.send(new DatagramPacket(buf, buf.length, server));
	}
	public void register() throws Exception {
		String msg = "register " + getLocalAddress() + " " + ds.getLocalPort();
		doSend(server, msg.getBytes());
	}
	public String getLocalAddress() throws Exception {
		InetAddress addr = InetAddress.getLocalHost();
		return addr.getHostAddress();
	}
}

 

 

共有父类:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.regex.Pattern;
public class UDPAgent implements Runnable {
	public static void main(String[] args) throws Exception {
		new UDPAgent(-1).start();
	}
	DatagramSocket ds;
	byte[] recbuf = new byte[1024];
	DatagramPacket rec = new DatagramPacket(recbuf, recbuf.length);
	public static String ipPattern = "([0-9]{1,3}.){3}[0-9]{1,3}";
	public static String portPattern = "[0-9]{1,5}";
	public static Pattern sendPattern = Pattern.compile("send " + ipPattern + " "
			+ portPattern + " .*");
	int port;
	public UDPAgent(int port) {
		this.port = port;
	}
	public void init() throws Exception {
		if (port < 1024 || port > 655535) {
			ds = new DatagramSocket();
		} else {
			ds = new DatagramSocket(port);
		}
	}
	public void start() throws Exception {
		println("start");
		println("LocalPort:" + port);
		init(); //构造服务器udp socket
		new Thread(this).start();//往自己输入的一个ip port发送东西 
		receive(); //循环接收客户端发来请求 打印出来
	}
	public void receive() {
		for (;;) {
			try {
				ds.receive(rec);
				String msg = new String(rec.getData(), rec.getOffset(), rec
						.getLength());
				String line = rec.getSocketAddress() + ":" + msg;
				println(line);
				//onReceive(rec);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	/*public void onReceive(DatagramPacket rec) {
	}*/

	public void doCommand(String cmd) throws Exception {
		// command:
		// 1. send xxx.xxx.xxx.xxx xxx *******************
		if (sendPattern.matcher(cmd).matches()) {
			doSend(cmd);
		}
	}
	public void doSend(String cmd) throws Exception {
		println("CMD: " + cmd);
		String[] s = cmd.split(" ", 4);
		int port = Integer.parseInt(s[2]);
		InetSocketAddress target = new InetSocketAddress(s[1], port);
		byte[] bs = s[3].getBytes();
		doSend(target, bs);
	}

	public void doSend(SocketAddress addr, byte[] data) throws Exception {
		DatagramPacket pack = new DatagramPacket(data, data.length, addr);
		ds.send(pack);
	}
	public void run() {
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				System.in));
		try {
			String line = reader.readLine();
			while (!"exit".equals(line)) {
				doCommand(line);
				line = reader.readLine();
			}
			System.exit(0);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void println(String s) {
		System.out.println(System.currentTimeMillis() + ":" + s);
	}
}

 

 当服务器启动日志:

1304581809784:start
1304581809784:LocalPort:2008

启动一个客户端在客户端日志:

1304581880627:start
此时在服务器端日志:

1304581809784:start
1304581809784:LocalPort:2008
1304581880674:/127.0.0.1:2465:register 99.6.150.31 2465

再启动一个客户端日志:

1304581964923:start

此时服务器端日志:

1304581809784:start
1304581809784:LocalPort:2008
1304581880674:/127.0.0.1:2465:register 99.6.150.31 2465
1304581964939:/127.0.0.1:2469:register 99.6.150.31 2469

 

相当于两个客户端连接服务器的IP都为99.6.150.31 端口分别为 2465和2469

 

由于本人在自己机子上模拟多客户端,其实还是在一个局域网内。

 

然后控制台到客户端1(即端口为2465那个),输入 send 99.6.150.31 2469 我要连接2469

这个时候,在客户端2(2469端口)会看到如下:1304582321669:/99.6.150.31:2465:我要连接2469

如果按照穿越原理,这种情况应该是不可能的,因为在2465的网关没有记录客户端1的信息,应该会被抛弃。但是这个步骤必做不可,原因是这样做,能在客户端1的网关记录客户端2的信息,这样客户端2就可以向客户端1网关发起请求而不被抛弃(我是这么认为的)。

最后用客户端2发起一个请求给客户端1,这个时候,由于客户端1的网关已经有记录客户端2的信息,所以不会被抛弃,这样通信链路就连上了。

 

接下来,如果客户端1要往客户端2发送信息只要往 99.6.150.31 2469发送。客户端2往客户端1发送只要往99.6.150.31 2465发送即可。

 

以上推论需要环境测试,欢迎大家测试告之结果。

 

 

 

 

分享到:
评论
2 楼 Ralfc 2012-05-04  
如果您有最研究的话,欢迎和我联系 r_evo@qq.com
1 楼 Ralfc 2012-05-04  
测试了这个程序,局域网内可以通过服务器端显示的端口号连接;外网的话只有服务器可以通过显示的端口号连接相应的客户端,而两台客户端之间无法通过IP与端口实现通信。

相关推荐

    p2p_TCP打洞_p2pudp穿墙_udp穿越nat_

    java源代码来说明tcp穿越NAT的原理。

    TCP-P2P.rar_P2P nat实现C++_TCP 打洞 _p2p TCP_tcp_打洞

    描述中的“TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞(附源代码).doc”进一步确认了这个压缩包包含了一篇文档,详细介绍了如何通过TCP协议进行P2P通信,NAT穿越的技术以及TCP打洞的实践方法,并且提供了源代码。...

    TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞

    TCP打洞分为两种主要类型:被动打洞和主动打洞。被动打洞依赖于服务器辅助,其中一个端点(称为客户端A)向公共服务器发送其内网NAT映射的IP和端口,然后服务器将这些信息转发给另一个端点(客户端B)。客户端B收到...

    c# 实现穿越防火墙udp打洞(仿qq即时通讯)

    C# UDP穿越NAT打洞,可在广域网实现仿qq即时通讯,点对点发送消息。

    UDPDaDong.rar_C# 丢包_TCP 打洞 _TCPClient_TCP打洞_udp聊天C

    UDP打洞测试程序,实现点对点信息传输,C#提供了Sockets来进行套接字的编程,里面包含了TcpClient和UdpClient。用过的大家都知道Tcp发送消息更安全,而Udp传送数据容易丢包,但速度快,能穿越防火墙。目前比较流行的...

    Netty UDP协议网络打洞实例

    Netty UDP协议网络打洞实例是利用Netty框架在UDP(User Datagram Protocol)协议基础上实现的一种穿透NAT(Network Address Translation)的技术。NAT技术在现代互联网中广泛使用,它允许内部网络中的设备共享一个...

    UDPTCP_打洞(穿越NAT)技术.docx

    本文档介绍了 UDP/TCP 打洞技术的实现原理和步骤,该技术用于穿越 NAT(Network Address Translation,网络地址转换),解决 P2P 通信领域中的 NAT 问题。该技术可以在 UDP 和 TCP 通信领域中应用,实现可靠的 P2P ...

    Sanguosha.rar_java swing三国杀_java三国穿越_sanguosha ai_三国杀_三国杀java Sw

    《基于Java Swing的三国杀游戏实现详解》 在IT领域,游戏开发是一项充满挑战与创新的工作,而将经典桌面游戏“三国杀”移植到计算机上则更是考验开发者的技术实力和对游戏规则的理解。本项目“Sanguosha.rar”就是...

    TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞源码

    本篇文章将深入探讨如何利用TCP实现P2P通信,以及TCP穿越NAT的策略,特别是TCP打洞技术。 首先,TCP实现P2P通信的核心在于对等节点之间的连接建立。在P2P网络中,每个节点都有一个私有IP地址,可能被NAT设备隐藏。...

    TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞源代码

    本文将详细探讨如何使用TCP实现P2P通信,以及TCP穿越NAT的方法,特别是TCP打洞技术,并提供相关的源代码参考。 首先,TCP实现P2P通信的关键在于建立可靠的端到端连接。在P2P网络中,每个节点都有一个私有IP地址,这...

    C#打洞demo

    "C#打洞demo"是一个示例项目,展示了如何使用C#编程语言实现P2P通信中的UDP打洞技术,以实现穿越路由器进行外网通信。 UDP(User Datagram Protocol)是传输层的一个无连接协议,它不保证数据的可靠传输,但具有低...

    java打洞技术

    因为当前 IPV4地址的缺乏 ,nat、防火墙的中介设备和不对称寻址建立起来的 p2p通信机制造成了地址访问的问题。 在 internet最初体系结构中,每个节点都有全球唯一的 ip地址,能够...此时我们需要的就是穿越技术。。。

    UDP-NAT.rar_nat_nat udp_udp 防火墙_udp打洞_打洞

    UDP穿越防火墙的例子,有助于学习UDP打洞原理哦。

    NET-P2P.rar_NET穿越_nat_p2p nat_传输模块类型

    标题中的"NET-P2P.rar_NET穿越_nat_p2p nat_传输模块类型"涉及了几个关键概念:NAT穿越、P2P通信以及不同类型的网络传输模块。下面将详细解释这些知识点。 首先,NAT(网络地址转换)是一种网络技术,用于在公共...

    TCP打洞—高质量的网络通信技巧

    通过分析和理解这些源代码,开发者可以深入学习TCP打洞的工作原理,并将其应用到实际的P2P应用程序中,比如实现高质量的文件传输服务,确保数据的可靠传输,同时减少丢包情况。"www.pudn.com.txt"可能是文档来源或者...

    UDP打洞源码及原理分析.zip

    而“UDP打洞源码及原理分析.rar”则可能更深入地讲解了UDP打洞的具体实现细节和背后的网络原理。通过学习这些资料,你可以更好地理解如何在实际项目中应用UDP打洞技术,解决内网通信问题。 需要注意的是,UDP打洞并...

    Nat.zip_NAT java_java nat

    【标题】"Nat.zip"指的是一个包含NAT(网络地址转换)相关程序的压缩文件,其后缀"_java"标明了这些程序是用Java编程语言编写的。"Nat"在计算机网络领域中是一个重要的概念,它允许有限的公网IP地址为多台内部设备...

    java 实现HTTP PROXY

    Java实现HTTP PROXY是一个常见的需求,特别是在开发网络应用或者测试环境中,我们可能需要通过代理服务器转发HTTP请求。本文将深入探讨如何使用Java编程语言来创建一个HTTP代理服务器,并且会涉及相关的源码分析。 ...

Global site tag (gtag.js) - Google Analytics