如何让它适用于p2p?

时间:2014-10-24 12:53:39

标签: java android p2p

有三个部分,服务器端,PC的客户端A和Android的客户端B. 逻辑是:
1.当客户端A和B连接到服务器时,他们将被通知另一个人的IP和端口 2.然后A将为B打一个洞并告诉服务器它已准备好从B接收。
3.服务器将告诉B A准备就绪 4.然后B将发送消息给A.

这只是一个简单的测试,测试环境是:
1.服务器有公共IP和端口
2.客户端A和客户端B处于不同的NAT

以下代码无效。两个对等方无法相互通信。如何让两个同行沟通?我会很感激你的每一条建议。

[编辑]
谢谢,@ kha。我第一次在这里发帖。我会详细说明这个过程 1. 3个部分也不例外。我没有错误。
2.两个客户端可以连接到服务器并从服务器接收另一个IP和端口 3.我关闭了Windows的防火墙。对于Android,我不知道该怎么做。
这两个客户只是无法沟通,没有任何其他例外 我是P2P的新手,所以我想找到更多帮助。

服务器端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Main {

    static EndPoint endPoint;
    static EndPoint endPoint2;

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) {
        try {
            DatagramSocket server = new DatagramSocket(5050);
            boolean isSend = false;
            while (true) {
                System.out.println("start receiving...");

                EndPoint ep = receiveMessage(server);

                if (endPoint == null) {
                    System.out.println("endPoint initialized");
                    endPoint = ep;
                } else if (endPoint2 == null) {
                    System.out.println("endPoint2 initialized");
                    endPoint2 = ep;
                } else {
                    if (!isSend) {//when A and B all connect to server, they will be notified another's ip and port
                        isSend = true;
                        System.out.println("send to each other");
                        sendEndPointMessage(server, endPoint, endPoint2);
                        sendEndPointMessage(server, endPoint2, endPoint);
                    } else {
                        if ("5".equals(ep.message)) {// client A is ready
                            System.out.println("client A is ready");
                            sendMessage(server, "6", endPoint2);// send B message that A is reay
                        }
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void sendEndPointMessage(DatagramSocket server, EndPoint epReceive, EndPoint epContent) {
        try {
            String sendStr = epContent.host + ";" + epContent.port;
            byte[] sendBuf = sendStr.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, epReceive.addr, epReceive.port);
            server.send(sendPacket);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static void sendMessage(DatagramSocket server, String msg, EndPoint ep) {
        try {
            byte[] sendBuf = msg.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, ep.addr, ep.port);
            server.send(sendPacket);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static EndPoint receiveMessage(DatagramSocket server) {
        try {
            byte[] recvBuf = new byte[1024];
            DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
            server.receive(recvPacket);

            String recvStr = new String(recvPacket.getData(), 0, recvPacket.getLength());
            int port = recvPacket.getPort();
            InetAddress addr = recvPacket.getAddress();

            System.out.println("EndPoint: host:" + recvPacket.getAddress() + ", port:" + port + ", message:" + recvStr);

            EndPoint endPoint = new EndPoint(addr, port, recvStr);
            return endPoint;
        } catch (IOException e) {

            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static class EndPoint {
        InetAddress addr;
        String host;
        int port;
        String message;

        public EndPoint(String host, int port, String message) {
            this.host = host;
            this.port = port;
            this.message = message;

            try {
                addr = InetAddress.getByName(host);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }

        public EndPoint(InetAddress host, int port, String message) {
            this.host = host.getHostAddress();
            this.port = port;
            this.message = message;

            addr = host;
        }
    }

}

PC的客户端A:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Main {
    public static String serverAddr = "xxx.xxx.xxx.xx";
    public static int serverPort = 5050;
    public static String peerIP;
    public static int peerPort;

    /**
     * @param args
     */
    public static void main(String[] args) {

        try {
            final DatagramSocket client = new DatagramSocket();

            sendMessage(client, "1", serverAddr, serverPort);

            while (true) {
                System.out.println("start receiving...");

                String recvStr = receiveMessage(client);

                if ("3".equals(recvStr)) {
                    sendMessage(client, "4", peerIP, peerPort);
                } else {
                    String[] peer = recvStr.split(";");
                    if (peer.length > 1) {// received peer ip and port
                        peerIP = peer[0];
                        peerPort = Integer.parseInt(peer[1]);
                        sendMessage(client, "4", peerIP, peerPort);//punch a hole for client B
                        sendMessage(client, "5", serverAddr, serverPort);//tell server I am ready
                        new Thread(new Runnable() {

                            @Override
                            public void run() {
                                for (int i = 0; i < 10; i++) {
                                    sendMessage(client, "4", peerIP, peerPort);//keep punch a hole for client B
                                    sendMessage(client, "5", serverAddr, serverPort);//keep telling server I am ready
                                    try {
                                        Thread.sleep(500);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }).start();
                    } else {
                        if ("7".equals(recvStr)) {// received from client B
                            sendMessage(client, "got from android", peerIP, peerPort);
                        }
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String receiveMessage(final DatagramSocket client) {
        try {
            byte[] recvBuf = new byte[1024];
            DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
            client.receive(recvPacket);
            String recvStr = new String(recvPacket.getData(), 0, recvPacket.getLength());
            String ip = recvPacket.getAddress().getHostAddress();
            int port = recvPacket.getPort();
            System.out.println("received from: host:" + ip + ", port:" + port + ", content:" + recvStr);
            return recvStr;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static void sendMessage(final DatagramSocket client, String sendStr, String ip, int port) {
        try {
            System.out.println("send out: host:" + ip + ", port: " + port + ", message:" + sendStr);
            byte[] sendBuf;
            sendBuf = sendStr.getBytes();
            InetAddress addr = InetAddress.getByName(ip);
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, addr, port);
            client.send(sendPacket);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

Android的客户端B:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;

public class MainActivity extends Activity {
    public String serverAddr = "xxx.xxx.xxx.xx";
    public int serverPort = 5050;
    public String peerIP;
    public int peerPort;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.connectServer).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        connectServer();
                    }
                }).start();

            }
        });
    }

    private void connectServer() {
        try {
            DatagramSocket client = new DatagramSocket();

            sendMessage(client, "2", serverAddr, serverPort);

            while (true) {
                System.out.println("start receiving...");

                String recvStr = receiveMessage(client);

                String[] peer = recvStr.split(";");
                if (peer.length > 1) {// received peer ip and port
                    peerIP = peer[0];
                    peerPort = Integer.parseInt(peer[1]);
                } else {
                    if ("6".equals(recvStr)) {//received from server that client A is ready                     
                        sendMessage(client, "7", peerIP, peerPort); // send message to client A                 
                    }
                }
            }

        } catch (SocketException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String receiveMessage(DatagramSocket client) throws IOException {
        try {
            byte[] recvBuf = new byte[1024];
            DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
            client.receive(recvPacket);
            String ip = recvPacket.getAddress().getHostAddress();
            int port = recvPacket.getPort();
            String recvStr = new String(recvPacket.getData(), 0, recvPacket.getLength());
            System.out.println("received from: host:" + ip + ", port:" + port + ", content:" + recvStr);
            return recvStr;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void sendMessage(DatagramSocket client, String sendStr, String ip, int port) {
        try {
            System.out.println("send out: host:" + ip + ", port:" + port + ", mesasge:" + sendStr);
            byte[] sendBuf;
            sendBuf = sendStr.getBytes();
            InetAddress addr = InetAddress.getByName(ip);
            DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, addr, port);
            client.send(sendPacket);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

1 个答案:

答案 0 :(得分:0)

我还有一台服务器需要测试。并且从客户端B找到与服务器A和服务器B相同的端口,NAT有两个不同的端口 我的NAT是一个对称的NAPT。所以我认为这是两个同行无法沟通的根本原因 @KunjanThadani,你是对的。