【发布时间】:2014-10-25 21:15:55
【问题描述】:
有 3 个部分,服务器端,PC 的客户端 A 和 android 的客户端 B。
逻辑是:
1.当客户端A和B连接到服务器时,会通知对方的ip和端口。
2. 然后A给B打一个洞,告诉服务器它已经准备好接收来自B的消息了。
3. 服务器会告诉 B A 准备好了。
4. 然后B会向A发送消息。
这只是一个简单的测试,测试环境有:
1.服务器有公网IP和端口
2.Client A和Client B在不同的NAT中
下面的代码不起作用。两个对等方无法相互通信。如何让两个peer通信?我会感激每一条建议。
[编辑]
谢谢,@kha。我第一次在这里发帖。我会详细说明过程。
1. 3个部分也不例外。我没有错误。
2.两个客户端可以连接到服务器并从服务器接收另一个的IP和端口。
3. 我关闭了 Windows 的防火墙。对于android,我不知道该怎么做。
4. 两个客户端就是不能通信,没有其他异常。
5. 我是 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();
}
}
}
【问题讨论】:
-
解释一下“不工作”是什么意思。
-
@kingdamian42 已修改,不工作意味着两个对等方无法相互通信。
-
哪个部分不起作用?你得到什么错误?他们都可以连接到您的服务器并获取彼此的IP地址吗?有防火墙问题吗?你有网络异常吗?您是否尝试过缩小问题范围并找出原因?
-
谢谢,@kha 我第一次在这里发帖。我会详细说明这个过程。 1. 3个部分也不例外。我没有错误。 2. 两个客户端可以连接到服务器,并从服务器接收另一个的 ip 和端口。 3. 我关闭了 Windows 的防火墙。对于android,我不知道该怎么做。 4. 两个客户端就是不能通信,没有其他异常。 5. 我是 P2P 新手,所以我想要更多的帮助来找到问题。
-
@kha,我又多了一台服务器进行测试。并且发现从具有相同端口的客户端B到服务器A和服务器B,NAT打开了两个不同的端口。我的 NAT 是对称 NAPT。所以我认为这是两个对等点无法通信的根本原因。感谢您的耐心。