`
iaiai
  • 浏览: 2196992 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java p2p打洞通信

    博客分类:
  • J2EE
 
阅读更多
因为当前 IPV4地址的缺乏 ,nat、防火墙的中介设备和不对称寻址建立起来的 p2p通信机制造成了地址访问的问题。

在 internet最初体系结构中,每个节点都有全球唯一的 ip地址,能够直接通信。可是随着节点的增多, ip地址使用紧张,他们需要中介设备如 nat连在一起。
私有网络中的节点可以直接连接到相同私有网络中的其他节点,也可以连接到全局地址空间中拥有全球唯一 ip地址的节点。。然而 nat通常只允许临时的向外连接申请,对于向内的申请会拒绝。这就造成了在 natA内网中的节点 A连接 natB内网中的节点 B时连接申请报到 natB时就被阻止了。此时我们需要的就是穿越技术。。。
 
总体来说穿越技术是利用一个公共服务器中转,使节点 A、 B都连接到中转服务器 S之后,通过 S中转 A发送到 B的数据报或者是中转连接申请,,使 A、 B对于 natA和 natB来说都是向外申请。。。
 
1、         中转数据报: A、 B都先向外与服务器 S建立接连,然后通过 S中转 A、 B之间的数据报。。
2、         反向连接:当 A、 B都与 S建立了连接,并且只有一个节点在 nat之后(假设 A在 natA之后)。。当 B向 A申请连接时,申请背 natA拒绝。 B可以向 S提出申请要与 A建立连接,然后 S向 A发出指令,通知 A主动向 B申请建立连接。。
【 UDP打洞】
1、 A、 B在同一个 nat之后:

用户 A让 S做介绍人来与 B建立对话
(1) A向 S发送一个消息请求与 B建立连接
(2) S使用 B的公共终端( 155.99.25.11: 62005)和私有终端( 10.1.1.3)响应 A
(3) 同时 S也想 B发送 A的公共终端( 155.99.25.11: 62000)和私有终端( 10.0.0.1),但是发送到公共终端的消息不一定能达到 B取决于 NAT是否支持“发夹”转化(回环转化)
(4) 如果 nat支持发夹转化的话,应用程序就可以免除私有和共有终端都要试图连接的复杂性。。

 
2、不同 NAT后面的节点

(1) 注册, A、 B都想服务器 S注册 natA安排了 62000端口用作 A和 S对话使用, natB安排了 31000端口用作 B和 S对话使用, A向 S的注册消息中报告了自己的私有终端 10.0.0.1: 4321这种情况下 A的公共终端是 155.99.25.11: 62000,同理 B的私有终端 10.1.1.3: 4321和公共终端 136.76.29.7: 31000
(2) A发送请求消息到 S,请求与 B建立连接,作为响应 S向 A发送了 B的私有终端和公共终端也向 B发送了 A的私有和公共终端。
(3) 既然 A、 B处在不同的子网中,那么 A、 B的私有终端是不能公共路由的,发送的消息肯能会发到自己子网中的 ip中(应为不同子网中的私有 ip可以相同)
(4) 当从 A发向 B的第一个消息到达 natA时, natA注意到这是一个新的外出会话, natA看到源地址是子网中地址,而目的地址是外网地址,所以 natA将从私有终端 10.0.0.1: 4321的外出会话转化到对应公共终端 155.99.25.11: 62000,这样 A的第一个到 B的公共终端的外出会话消息就在 natA上“打了一个洞”。新的 UDP会话由 A的私有网络上的终端 10.0.0.1: 4321/138.76.29.7: 31000和 internet上的公共终端 155.99.25.11: 62000/138.76.29.7:31000标识,同理 B也建立了对 A的私有、公共连接标识。
(5) 如果 A发向 B的公共终端的消息在 B发向 A的第一个消息穿过 B自己的 natB之前到达了 natB的话, natB会认为 A的内入消息是禁止的,丢弃 B的请求消息,但是 B的请求消息在 natB上为 A打了一洞,此时洞双向打开,通信可以进行下去了。。。

3、多级 NAT后面的节点:

( 1) A、 B都建立与 S的向外连接
( 2)最终连接目的:
   Aà B    10.0.0.1à 10.0.1.2:55000
   Bà A    10.0.0.3à 10.0.1.1:45000
( 3)但是在此时 A、 B无法知道伪公众终端 10.0.1.2:55000和 10.0.1.1:45000。 S只看到了 155.99.25.11: 32000和 155.99.25.11: 62005。
( 4)此时相应的 A、 B也只知道 155.99.25.11: 32000和 155.99.25.11: 62005
( 5)只能依赖 natC的发夹转化。
     当 A-à B,即 10.0.0.1—>155.99.25.11: 62005时 natA将数据报中源地址 10.0.0.1转化为 10.0.1.1然后发送到 natC,当 natC发现目的地址 ip是 155.99.25.11是自己转化过的 ip后, natC就会转化数据报中的源地址和目的地址,再发送到私有网络中。 155.99.25.11: 62000--à 10.0.1.2: 55000
( 6)当数据报到 B私有网络时,同样方法进行转化。。


UDPServer.java:
package org.iaiai.test;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 
 * <br/>
 * Title: UDPServer.java<br/>
 * E-Mail: 176291935@qq.com<br/>
 * QQ: 176291935<br/>
 * Http: iaiai.iteye.com<br/>
 * Create time: 2013-1-29 上午11:11:56<br/>
 * <br/>
 * @author 丸子
 * @version 0.0.1
 */
public class UDPServer {

    public static void main(String[] args) {
        try {
            DatagramSocket server = new DatagramSocket(2008);
            byte[] buf = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buf, buf.length);

            String sendMessage132 = "";
            String sendMessage129 = "";
            int port132 = 0;
            int port129 = 0;
            InetAddress address132 = null;
            InetAddress address129 = null;
            for (;;) {
                server.receive(packet);

                String receiveMessage = new String(packet.getData(), 0, packet.getLength());
                System.out.println(receiveMessage);
                //接收到clientA
                if (receiveMessage.contains("132")) {
                    port132 = packet.getPort();
                    address132 = packet.getAddress();
                    sendMessage132 = "host:" + address132.getHostAddress() + ",port:" + port132;
                }
                //接收到clientB
                if (receiveMessage.contains("129")) {
                    port129 = packet.getPort();
                    address129 = packet.getAddress();
                    sendMessage129 = "host:" + address129.getHostAddress() + ",port:" + port129;
                }
                //两个都接收到后分别A、B址地交换互发
                if (!sendMessage132.equals("") && !sendMessage129.equals("")) {
                    send132(sendMessage129, port132, address132, server);
                    send129(sendMessage132, port129, address129, server);
                    sendMessage132 = "";
                    sendMessage129 = "";
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void send129(String sendMessage132, int port132, InetAddress address132, DatagramSocket server) {
        try {
            byte[] sendBuf = sendMessage132.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address132, port132);
            server.send(sendPacket);
            System.out.println("消息发送成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void send132(String sendMessage129, int port129, InetAddress address129, DatagramSocket server) {
        try {
            byte[] sendBuf = sendMessage129.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address129, port129);
            server.send(sendPacket);
            System.out.println("消息发送成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


UDPClientA.java:
package org.iaiai.test;

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

/**
 * 
 * <br/>
 * Title: UDPClientA.java<br/>
 * E-Mail: 176291935@qq.com<br/>
 * QQ: 176291935<br/>
 * Http: iaiai.iteye.com<br/>
 * Create time: 2013-1-29 上午11:11:56<br/>
 * <br/>
 * @author 丸子
 * @version 0.0.1
 */
public class UDPClientA {

    public static void main(String[] args) {
        try {
            // 向server发起请求
            SocketAddress target = new InetSocketAddress("10.1.11.137", 2008);
            DatagramSocket client = new DatagramSocket();
            String message = "I am UPDClinetA 192.168.85.132";
            byte[] sendbuf = message.getBytes();
            DatagramPacket pack = new DatagramPacket(sendbuf, sendbuf.length, target);
            client.send(pack);
            // 接收请求的回复,可能不是server回复的,有可能来自UPDClientB的请求内
            receive(client);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //接收请求内容
    private static void receive(DatagramSocket client) {
        try {
            for (;;) {
                byte[] buf = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                client.receive(packet);
                String receiveMessage = new String(packet.getData(), 0, packet.getLength());
                System.out.println(receiveMessage);
                int port = packet.getPort();
                InetAddress address = packet.getAddress();
                String reportMessage = "tks";
                //获取接收到请问内容后并取到地址与端口,然后用获取到地址与端口回复内容
                sendMessaage(reportMessage, port, address, client);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //回复内容
    private static void sendMessaage(String reportMessage, int port, InetAddress address, DatagramSocket client) {
        try {
            byte[] sendBuf = reportMessage.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address, port);
            client.send(sendPacket);
            System.out.println("消息发送成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


UDPClientB.java
package org.iaiai.test;

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

/**
 * 
 * <br/>
 * Title: UDPClientB.java<br/>
 * E-Mail: 176291935@qq.com<br/>
 * QQ: 176291935<br/>
 * Http: iaiai.iteye.com<br/>
 * Create time: 2013-1-29 上午11:11:56<br/>
 * <br/>
 * @author 丸子
 * @version 0.0.1
 */
public class UDPClientB {

    public static void main(String[] args) {
        try {
            //向server发起请求
            SocketAddress target = new InetSocketAddress("10.1.11.137", 2008);
            DatagramSocket client = new DatagramSocket();
            String message = "I am UDPClientB 192.168.85.129";
            byte[] sendbuf = message.getBytes();
            DatagramPacket pack = new DatagramPacket(sendbuf, sendbuf.length, target);
            client.send(pack);
            //接收server的回复内容
            byte[] buf = new byte[1024];
            DatagramPacket recpack = new DatagramPacket(buf, buf.length);
            client.receive(recpack);
            //处理server回复的内容,然后向内容中的地址与端口发起请求(打洞)
            String receiveMessage = new String(recpack.getData(), 0, recpack.getLength());
            String[] params = receiveMessage.split(",");
            String host = params[0].substring(5);
            String port = params[1].substring(5);
            System.out.println(host + ":" + port);
            sendMessage(host, port, client);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //向UPDClientA发起请求(在NAT上打孔)
    private static void sendMessage(String host, String port, DatagramSocket client) {
        try {
            SocketAddress target = new InetSocketAddress(host, Integer.parseInt(port));
            for (;;) {
                String message = "I am master 192.168.85.129 count test";
                byte[] sendbuf = message.getBytes();
                DatagramPacket pack = new DatagramPacket(sendbuf, sendbuf.length, target);
                client.send(pack);
                //接收UDPClientA回复的内容
                receive(client);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //收到UDPClientA的回复内容,穿透已完成
    private static void receive(DatagramSocket client) {
        try {
            for (;;) {
                //将接收到的内容打印
                byte[] buf = new byte[1024];
                DatagramPacket recpack = new DatagramPacket(buf, buf.length);
                client.receive(recpack);
                String receiveMessage = new String(recpack.getData(), 0, recpack.getLength());
                System.out.println(receiveMessage);

                //记得重新收地址与端口,然后在以新地址发送内容到UPDClientA,就这样互发就可以了。
                int port = recpack.getPort();
                InetAddress address = recpack.getAddress();
                String reportMessage = "I am master 192.168.85.129 count test";

                //发送消息
                sendMessage(reportMessage, port, address, client);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void sendMessage(String reportMessage, int port, InetAddress address, DatagramSocket client) {
        try {
            byte[] sendBuf = reportMessage.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address, port);
            client.send(sendPacket);
            System.out.println("send success");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 大小: 29.6 KB
  • 大小: 38.3 KB
  • 大小: 41.1 KB
分享到:
评论

相关推荐

    java udp p2p nat 等打洞技术实现通信,已测试成功

    总结,通过Java实现的UDP打洞技术,可以克服NAT的障碍,实现子网间的P2P通信。这在分布式系统、在线游戏、文件共享等领域都有广泛应用。在实际开发中,还需要考虑兼容性、安全性以及网络环境的复杂性。

    java打洞技术

    因为当前 IPV4地址的缺乏 ,nat、防火墙的中介设备和不对称寻址建立起来的 p2p通信机制造成了地址访问的问题。 在 internet最初体系结构中,每个节点都有全球唯一的 ip地址,能够直接通信。可是随着节点的增多, ip...

    UDP打洞的实现代码

    UDP打洞技术是一种在P2P网络中实现端到端通信的方法,特别是在存在网络地址转换(NAT)的环境中。NAT使得私有网络内的设备无法直接与其他网络的设备通信,因为它们都共享一个公共IP地址。UDP打洞通过利用NAT的某些...

    java编的P2P程序+源码.rar

    【标题】"java编的P2P程序+源码.rar" 涉及的主要知识点是Java编程语言在实现P2P(对等网络)程序上的应用,以及如何通过UDP打洞技术穿越NAT(网络地址转换)进行通信。P2P网络是一种分布式网络架构,其中每个节点...

    Netty UDP协议网络打洞实例

    总之,通过Netty和UDP协议实现的网络打洞实例,不仅展示了Netty的强大功能,还揭示了网络通信中解决NAT障碍的策略和技术。开发者可以利用这些知识,构建出高效、可靠的P2P应用,如在线游戏、音视频通话等。

    测试udp打洞

    P2P打洞技术,也称为UDP打洞或STUN(Session Traversal Utilities for NAT),是为了让两个处于NAT后的设备能够发现彼此并建立直接连接的一种方法。 在P2P UDP打洞过程中,主要涉及以下几个关键知识点: 1. **NAT...

    java-udp-qq聊天源码,p2p通信完全实现

    java-udp-qq聊天源码,p2p通信完全实现 UDP打洞实现了子网间的穿透功能,首先在一台拥有公网IP服务器上运行server,在不同的两个子网PC上运行client,输入服务器IP,即可进行打洞,实现不同子网的通信。

    udp 打洞示例代码 包含服务器 客户端

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有网络内的主机之间直接通信的方法。在互联网上,许多设备由于连接到ISP时采用了NAT,它们的公网IP实际上是路由器分配的内部IP,因此不能直接与其他网络的...

    P2p之UDP穿透NAT的原理与实现代码

    在提供的压缩包中,"P2P之UDP穿透NAT的原理与实现源代码"很可能是用某种编程语言(如C++、Python或Java)实现的示例代码,包含具体的打洞算法和信令交互逻辑。通过阅读和理解这些代码,可以更深入地了解UDP穿透NAT的...

    udp tcp打洞测试.zip

    "打洞"(Punching Hole)是P2P网络中的一种技术,用于解决NAT(Network Address Translation)设备导致的通信问题。NAT设备通常会隐藏内部网络中的设备,使得外部网络无法直接与其通信。UDP打洞通过两个位于NAT后的...

    STUN协议的java实现,stun4j

    STUN (Session Traversal Utilities for NAT) 协议是一种用于网络地址转换(NAT)穿越的技术,它允许位于NAT后的设备发现其公网IP和端口,从而在P2P应用中建立直接通信。Java实现的STUN客户端库,如stun4j,对于...

    udp打洞代码的rar文件

    P2P(对等网络)技术通常会用到UDP打洞,因为它允许对等节点直接通信,减少中心服务器的压力,提高网络效率。在实际应用中,比如在线游戏、视频通话、文件分享等场景,都需要使用UDP打洞技术来实现穿越NAT的高效通信...

    udp打洞 客户端和服务端 附说明文档

    UDP打洞技术是一种在内网环境下实现外网访问内网服务的方法,主要应用于P2P通信、游戏联机等场景。UDP(User Datagram Protocol)是一种无连接的、不可靠的传输层协议,它以较小的开销提供了快速的数据传输。在内网...

    NAT探测 使用stun协议 java和python版本

    5. 根据NAT类型,客户端可以采取不同的策略来实现P2P通信,比如使用UDP打洞或者通过TURN服务器转发。 在开发P2P应用时,NAT探测和STUN协议是必不可少的组成部分,它们使得内部网络的设备能够有效地与其他网络节点...

    P2P之UDP穿透NAT P2PClient

    2. **ICE(Interactive Connectivity Establishment)**:ICE是一种更全面的方法,结合了UDP打洞和STUN(Session Traversal Utilities for NAT)服务器。STUN服务器用于获取内置于NAT中的设备的公网映射地址。ICE...

    多线程实现P2P服务器

    打洞成功"是指在P2P网络中实现NAT穿透(NAT Traversal),以便两个位于内网的节点可以直接通信。在NAT环境下,每个设备都有一个公共IP地址和私有IP地址,多线程在这里的作用是协助进行端口映射和通信测试,确保...

    P2P聊天程序(UDP穿越NAT)

    - 打洞和TURN中继模块:根据NAT类型,尝试打洞或使用TURN服务器进行通信。 通过分析和理解这个源代码,我们可以深入学习P2P通信和UDP穿越NAT的实践,这对于开发分布式系统、游戏网络、实时通信应用等领域具有很高的...

    P2P聊天工具原来QQ是这个原理

    QQ通过UDP打洞(UDP Hole Punching)或STUN(Simple Traversal of UDP through NATs)服务器协助,实现内网用户的端口映射,让两个内网用户能直接通信。 2. **分布式哈希表(DHT)**:QQ可能利用DHT技术来存储和...

    Nat.zip_NAT java_java nat

    它涉及到了网络通信中的端口映射、UDP打洞等技术。在这个实验中,需要三台电脑,其中两台被配置为模拟不同的NAT环境,另一台则作为服务器或者客户端,以便测试NAT穿越的实现效果。此外,还需要两台路由器进行配合,...

    基于Java的实例源码-穿越NAT方案 JSTUN.zip

    3. UDP打洞:NAT穿透的关键在于创建两个位于不同NAT之后的设备之间的直接UDP连接。JSTUN会尝试通过发送数据包来在NAT上“打洞”,创建持久的UDP通道。 4. 代理服务器:在某些情况下,可能需要借助STUN服务器或TURN...

Global site tag (gtag.js) - Google Analytics