There are 3 sections, server side, client A for PC and client B for android.
The logic is:
1. When client A and B connect to server, they will be notified another's ip and port.
2. Then A will punch a hole for B and tell the server that it is ready for receiving from B.
3. server will tell B that A is ready.
4. Then B will send message to A.
This is just a simple test, the test environment are:
1. Server has a public IP and port
2. Client A and Client B are in different NAT
The code below is not working. Two peers can't communicate each other. How to make the two peer communicate? I will appreciate every piece of advice.
[Edit]
Thanks, @kha. First time I post here.I will detail the process.
1. No exception from the 3 sections. I got no error.
2. Two clients can connect to server and receive another's ip and port from server.
3. I turned off the firewall for Windows. For android, I don't know how to do this.
4. The two clients just can't communicate, no any other exception.
5. I am new for P2P, so I wanna more help with finding the problem.
Server side code:
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;
}
}
}
Client A for PC:
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();
}
}
}
Client B for Android:
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();
}
}
}
I got one more server for test. And find that from client B with the same port to the server A and server B, there are two different ports opened by NAT.
My NAT is a Symmetric NAPT. So I think this is the root reason that two peers can't communicate.
@KunjanThadani, you are right.