问题:端口是否错误(进行udp冲击)?
我有一台Java服务器,用于保存连接客户端和服务器的ip和端口。 ip和ports被发送到客户端和服务器,因此他们可以启动udp打孔。我使用2台计算机连接到同一个NAT。但它拒绝工作。
java服务器日志说:
Send server global ip and port 61721 to client
Send client global ip and port 63105 to server
服务器和客户端开始发送udp数据包,但一段时间后它们会超时。 我使用Wireshark检查打孔,客户端日志如下所示:
Source Destination Info
192.168.1.78 206.217.173.176 UDP source port: 50701 Destination Port: 61721
192.168.1.78 206.217.173.176 UDP source port: 50701 Destination Port: 61721
... + 50 more
服务器日志:
Source Destination Info
192.168.1.73 206.217.173.176 UDP source port: 6510 Destination Port: 63105
192.168.1.73 206.217.173.176 UDP source port: 6510 Destination Port: 63105
... + 50 more
在服务器日志中找不到来自客户端的数据包。并且在客户端日志中找不到服务器数据包。
这是Java服务器代码:
完整代码可在以下网址找到:https://github.com/Parakoopa/GMnet-GATE-PUNCH/tree/master/src/main/java/org/parakoopa/gmnetgate/punch
Server.java
package org.parakoopa.gmnetgate.punch;
import com.google.gson.annotations.Expose;
import java.net.Socket;
public class Server {
/**
* Contains the IP of this server
*/
@Expose private String ip = "";
/**
* Contains the Ports of the Server.
* A port is assigned to an ip, so only one ip per server is possible.
*/
private Integer port = 0;
/**
* Contains the TCP Sockets of the Server.
* For sending the connection requests to the servers.
*/
private Socket tcp_socket = null;
/**
* The 8 data strings.
*/
@Expose private String data1 = "";
@Expose private String data2 = "";
@Expose private String data3 = "";
@Expose private String data4 = "";
@Expose private String data5 = "";
@Expose private String data6 = "";
@Expose private String data7 = "";
@Expose private String data8 = "";
/**
* Time the server was created
*/
@Expose private long createdTime;
public Server(String ip) {
this.createdTime = System.currentTimeMillis() / 1000L;
this.ip = ip;
}
/**
* Contains the Ports of the Server.
* A port is assigned to an ip, so only one ip per server is possible.
*/
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
/**
* Contains the TCP Sockets of the Server.
* For sending the connection requests to the servers.
*/
public Socket getTCPsocket() {
return tcp_socket;
}
public void setTCPsocket(Socket tcp_socket) {
this.tcp_socket = tcp_socket;
}
public String getData1() {
return data1;
}
public void setData1(String data1) {
this.data1 = data1;
}
public String getData2() {
return data2;
}
public void setData2(String data2) {
this.data2 = data2;
}
public String getData3() {
return data3;
}
public void setData3(String data3) {
this.data3 = data3;
}
public String getData4() {
return data4;
}
public void setData4(String data4) {
this.data4 = data4;
}
public String getData5() {
return data5;
}
public void setData5(String data5) {
this.data5 = data5;
}
public String getData6() {
return data6;
}
public void setData6(String data6) {
this.data6 = data6;
}
public String getData7() {
return data7;
}
public void setData7(String data7) {
this.data7 = data7;
}
public String getData8() {
return data8;
}
public void setData8(String data8) {
this.data8 = data8;
}
public long getCreatedTime() {
return createdTime;
}
}
TCPConnection.java:
package org.parakoopa.gmnetgate.punch;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Handles incoming TCP connections.
* Stores server sockets and on client request send server ports to client and
* client ports to server via the stored socket.
* @author Parakoopa
*/
public class TCPConnection implements Runnable {
private Mediator main;
private Socket client;
private ServerSocket server;
/** Game Maker Studio seperates strings in buffers with this char (buffer_string). */
private char gm_string_seperator = 0;
/** True, if the "reg" command was used on this connection **/
private boolean isServer = false;
/**
* Set's up a new connection listener that handles all packets of one connection.
* @param main Mediator class instance that this server was created with.
* @param client Socket that the client is connected to.
* @param server Our TCP server socket the client is connected to. (not actually used)
*/
public TCPConnection(Mediator main, Socket client, ServerSocket server) {
this.server = server;
this.client = client;
this.main = main;
}
/**
* Starts listening for incoming packets and responds to it.
*/
@Override
public void run() {
String debug_string = this.client.getInetAddress().getHostAddress()+":"+this.client.getPort()+" | TCP | ";
Mediator.log(debug_string+" Connected!",true);
try {
//TcpNoDelay configures the socket to transfer messages immediately, otherwise GM:S won't pick them up
this.client.setTcpNoDelay(true);
//Input and Output streams. We write bytes out and take Strings in.
OutputStream out = client.getOutputStream();
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
String inputLine;
Server serverObj;
//Process all packets. This while loop will stop when the peer disconnected.
while ((inputLine = in.readLine()) != null) {
//This will kill Threads (or commands) if the client don't send
//all of the data expected. Needed otherwise this could lead
//to many hanging threads.
client.setSoTimeout(1000);
//Cleans string, it might contain some garbage characters.
inputLine = inputLine.replaceAll("\\p{C}", "");
switch (inputLine) {
case "reg2":
Mediator.log(debug_string+" Server wants to register!",true);
//A server wants to register/reregister. We put the socket in the socket map so we can use it later.
//Check version compatibility
String version = in.readLine().replaceAll("\\p{C}", "");
Mediator.log(debug_string+" Version: "+version,true);
if (!(Mediator.versionCompare(version,Mediator.getUdphpMin()) >= 0)) {
//For now just silently end the connection.
//Proper error messages will follow in the next release
Mediator.log(debug_string+" Server not accepted. Version too old.",true);
client.close();
return;
}
Mediator.log(debug_string+" Server registered!",false);
serverObj = this.main.getServer(this.client.getInetAddress().getHostAddress());
this.isServer = true;
serverObj.setTCPsocket(this.client);
//Write the 8 data strings
serverObj.setData1(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 1: "+serverObj.getData1(),true);
serverObj.setData2(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 2: "+serverObj.getData2(),true);
serverObj.setData3(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 3: "+serverObj.getData3(),true);
serverObj.setData4(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 4: "+serverObj.getData4(),true);
serverObj.setData5(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 5: "+serverObj.getData5(),true);
serverObj.setData6(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 6: "+serverObj.getData6(),true);
serverObj.setData7(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 7: "+serverObj.getData7(),true);
serverObj.setData8(in.readLine().replaceAll("\\p{C}", ""));
Mediator.log(debug_string+" Data 8: "+serverObj.getData8(),true);
break;
case "connect":
//A client wants to connect. Now the interesting part begins
//Wait for next line that contains the requested IP adress.
String requested_server = in.readLine().replaceAll("\\p{C}", "");
String debug_string2 = debug_string + " Client <-> "+requested_server+" ->";
Mediator.log(debug_string2+" Connecting...",false);
if (this.main.getServerMap().containsKey(requested_server)) {
//SERVER FOUND
serverObj = this.main.getServer(requested_server);
//get server connection socket from the map (stored above)
Socket gameserver = serverObj.getTCPsocket();
if (!gameserver.isClosed()) {
String connect_to_server = requested_server;
//Get server port
int connect_to_port = serverObj.getPort();
//Send server port to client
Mediator.log(debug_string2+" Found server",true);
Mediator.log(debug_string2+" Send server port "+connect_to_port+" to client",true);
out.write((byte) 255);
out.write((connect_to_server+this.gm_string_seperator).getBytes());
out.write((String.valueOf(connect_to_port)+this.gm_string_seperator).getBytes());
//Send buffer to client
out.flush();
//Get client port
Client clientObj = this.main.getClient(this.client.getInetAddress().getHostAddress());
int connect_to_port_server = clientObj.getPort();
Mediator.log(debug_string2+" Send client port "+connect_to_port_server+" to server",true);
//Get an output stream for the server socket. We will contact the server with this.
OutputStream out_server = gameserver.getOutputStream();
out_server.write((byte) 255);
out_server.write((this.client.getInetAddress().getHostAddress()+this.gm_string_seperator).getBytes());
out_server.write(String.valueOf(connect_to_port_server+this.gm_string_seperator).getBytes());
//Send buffer to server
out_server.flush();
//We are done! Client and Server now connect to each other and the hole is punched!
Mediator.log(debug_string2+" CONNECTED!",false);
} else {
//SERVER FOUND BUT SOCKET IS DEAD
Mediator.log(debug_string+" CONNECTION FAILED - Server not reachable",false);
out.write((byte) 254);
out.flush();
}
} else {
//SERVER NOT FOUND
Mediator.log(debug_string+" CONECTION FAILED - Server not found",false);
out.write((byte) 254);
out.flush();
}
this.main.destroyClient(this.client.getInetAddress().getHostAddress());
break;
case "lobby2":
if (Mediator.isLobby() || Mediator.isTesting()) {
Mediator.log(debug_string+" Sending lobby based on requested filters",true);
HashMap<String, Server> servers = new HashMap<String, Server>(main.getServerMap());
String filter_data1 = in.readLine().replaceAll("\\p{C}", "");
String filter_data2 = in.readLine().replaceAll("\\p{C}", "");
String filter_data3 = in.readLine().replaceAll("\\p{C}", "");
String filter_data4 = in.readLine().replaceAll("\\p{C}", "");
String filter_data5 = in.readLine().replaceAll("\\p{C}", "");
String filter_data6 = in.readLine().replaceAll("\\p{C}", "");
String filter_data7 = in.readLine().replaceAll("\\p{C}", "");
String filter_data8 = in.readLine().replaceAll("\\p{C}", "");
final String filter_sortby = in.readLine().replaceAll("\\p{C}", "");
final String filter_sortby_dir = in.readLine().replaceAll("\\p{C}", "");
String filter_limit = in.readLine().replaceAll("\\p{C}", "");
//Skip servers with <INV> gamename (this might happen if a server was created using UDP connection but never initialized via TCP)
//TODO: Remove these invalid servers after some time.
Iterator<Map.Entry<String, Server>> iterInv = servers.entrySet().iterator();
while (iterInv.hasNext()) {
Map.Entry<String, Server> entry = iterInv.next();
if (entry.getValue().getData1().equals("<INV>")) {
iterInv.remove();
}
}
if (!"".equals(filter_data1)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData1().equals(filter_data1)) {
iter.remove();
}
}
}
if (!"".equals(filter_data2)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData2().equals(filter_data2)) {
iter.remove();
}
}
}
if (!"".equals(filter_data3)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData3().equals(filter_data3)) {
servers.remove(entry.getKey());
}
}
}
if (!"".equals(filter_data4)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData4().equals(filter_data4)) {
iter.remove();
}
}
}
if (!"".equals(filter_data5)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData5().equals(filter_data5)) {
iter.remove();
}
}
}
if (!"".equals(filter_data6)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData6().equals(filter_data6)) {
iter.remove();
}
}
}
if (!"".equals(filter_data7)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData7().equals(filter_data7)) {
iter.remove();
}
}
}
if (!"".equals(filter_data8)) {
Iterator<Map.Entry<String, Server>> iter = servers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Server> entry = iter.next();
if (!entry.getValue().getData8().equals(filter_data8)) {
iter.remove();
}
}
}
Server[] arr = servers.values().toArray(new Server[servers.values().size()]);
Arrays.sort(arr, new Comparator<Server>() {
@Override
public int compare(Server o1, Server o2) {
int mp = 1;
int rt = 0;
if ("ASC".equals(filter_sortby_dir)) {
mp = -1;
}
switch (filter_sortby) {
default:
case "date":
rt = new Long(o1.getCreatedTime()).compareTo(o2.getCreatedTime()) * mp;
break;
case "data1":
rt = o1.getData1().compareTo(o2.getData1()) * mp;
break;
case "data2":
rt = o1.getData2().compareTo(o2.getData2()) * mp;
break;
case "data3":
rt = o1.getData3().compareTo(o2.getData3()) * mp;
break;
case "data4":
rt = o1.getData4().compareTo(o2.getData4()) * mp;
break;
case "data5":
rt = o1.getData5().compareTo(o2.getData5()) * mp;
break;
case "data6":
rt = o1.getData6().compareTo(o2.getData6()) * mp;
break;
case "data7":
rt = o1.getData7().compareTo(o2.getData7()) * mp;
break;
case "data8":
rt = o1.getData8().compareTo(o2.getData8()) * mp;
break;
}
return rt;
}
});
if (!"".equals(filter_limit) && Integer.valueOf(filter_limit) <= arr.length) {
arr = Arrays.copyOfRange(arr, 0, Integer.valueOf(filter_limit));
}
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(arr);
out.write((byte) 249);
out.write(json.getBytes());
out.write(10);
//Send buffer to server
out.flush();
}
break;
case "istesting":
out.write((byte) 248);
if (Mediator.isTesting()) {
Mediator.log(debug_string+" Sending if testing is enabled",true);
out.write((byte) 1);
} else {
out.write((byte) 0);
}
//Send buffer
out.flush();
break;
case "testinginfos":
out.write((byte) 247);
if (Mediator.isTesting()) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
out.write(Mediator.getName().getBytes());
out.write(10);
out.write(Mediator.getVersion().getBytes());
out.write(10);
out.write(Mediator.getUdphpMin().getBytes());
out.write(10);
Mediator.log(debug_string+" Sending testing information",true);
} else {
out.write((byte) 0);
}
//Send buffer
out.flush();
break;
case "version":
out.write((byte) 246);
out.write(Mediator.getVersion().getBytes());
out.write(10);
Mediator.log(debug_string+" Sending version information",true);
//Send buffer
out.flush();
break;
default:
//Ignore unknown commands (client disconnection will cause an unknown command)
break;
}
//Disable timout again and wait for next command
client.setSoTimeout(0);
}
client.close();
Mediator.log(debug_string+" Disconnected!",true);
//Cleanup, when they loose TCP connection, this data can't be used anymore, so it's safe to remove
if (this.isServer) {
this.main.destroyServer(this.client.getInetAddress().getHostAddress());
Mediator.log(debug_string+" Server deleted!",false);
}
} catch (Exception ex) {
Mediator.log(debug_string+" Disconnected (e: "+ex.getClass().getName()+")",true);
//Cleanup, when they loose TCP connection, this data can't be used anymore, so it's safe to remove
if (this.isServer) {
this.main.destroyServer(this.client.getInetAddress().getHostAddress());
Mediator.log(debug_string+" Server deleted!",false);
}
}
}
}
答案 0 :(得分:0)
没有错的端口。我的提供商在我背后更新了NAT。他们使它更“安全”。我的NAT不再可能使用UDP Punch了,因为它将打卡视为攻击并阻止它。