[英]Java TCP client-server NAT Connection Refused
我最近开始制作2D Java游戏,并在2天前开始制作tcp服务器,现在所有其他问题都已解决,我想解决一个事实,即客户端只能在同一服务器上连接到服务器设备和使用设备静态ip的设备,尽管它无法使用我的wan ip地址进行连接,但是我已转发了端口,并在许多端口检查器网站上进行了检查,它们都可以看到我的服务器,我的防火墙也被禁用,但是客户端可以没有看到使用wan ip的服务器,我在同一端口上制作了一个minecraft服务器(Minecraft服务器也是tcp),其他服务器则可以使用wan ip进行连接。 当客户端尝试使用我的wan ip进行连接时,它会给出Connection Refused异常。 我究竟做错了什么?
客户端(无法通过nat连接到服务器):
package com.diedericksclan.main.network;
import java.io.*;
import java.net.*;
import java.util.Enumeration;
public class ClientThread extends Thread {
private ClientHandler client;
private Socket socket;
private InetSocketAddress address;
private int megabyte = 1024 * 1024;
private DataInputStream in;
private DataOutputStream out;
public ClientThread(ClientHandler client, InetSocketAddress address) {
this.client = client;
this.address = address;
socket = new Socket();
try {
socket.setSendBufferSize(megabyte);
socket.setSendBufferSize(megabyte);
socket.setTcpNoDelay(true);
socket.setReuseAddress(true);
socket.bind(new InetSocketAddress(this.getIP(), 0));
System.out.println(socket.getLocalAddress().getHostAddress() + ":" + socket.getLocalPort() + " is a new client!");
socket.connect(address);
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private InetAddress getIP() throws SocketException {
Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
NetworkInterface ni;
while (nis.hasMoreElements()) {
ni = nis.nextElement();
if (!ni.isLoopback() && ni.isUp()) {
for (InterfaceAddress ia : ni.getInterfaceAddresses()) {
if (ia.getAddress().getAddress().length == 4) {
return ia.getAddress();
}
}
}
}
return null;
}
long starttime;
long endtime;
long overall;
public void run() {
byte[] data;
while(true) {
try {
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
data = new byte[in.readInt() - 4];
in.read(data);
client.parsePacket(data, socket.getInetAddress(), socket.getPort());
endtime = System.nanoTime();
overall = endtime - starttime;
//System.out.println("CLIENT >> SERVER >> CLIENT - Time was: " + overall + " nano seconds!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public synchronized void sendData(byte[] data) {
try {
try { socket.connect(address); } catch (IOException e) {}
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
starttime = System.nanoTime();
out.writeInt(data.length + 4);
out.write(data);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void serverShutdown() {
try {
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器(除客户端外的所有内容均可看到):
package com.diedericksclan.main.network;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import com.diedericksclan.main.network.handling.PlayerMP;
public class ServerThread extends Thread {
private ServerHandler server;
private ServerSocket dataSocket;
private Socket socket;
private InetSocketAddress address;
private int megabyte = 1024 * 1024;
private int dedicated = 1024;
public int RAM = megabyte * dedicated;
private ArrayList<Client> clients = new ArrayList<Client>();
public ServerThread(ServerHandler server, String serverIP, int ram, int backlog) throws Exception {
super(serverIP);
this.server = server;
this.dedicated = ram;
String ip = "localhost";
int port = 2048;
if(serverIP.contains(":")) {
ip = serverIP.split(":")[0];
port = Integer.parseInt(serverIP.split(":")[1]);
} else {
ip = serverIP;
port = 2048;
}
this.dataSocket = new ServerSocket();
this.dataSocket.setReuseAddress(true);
this.address = new InetSocketAddress(InetAddress.getByName(ip), port);
this.dataSocket.bind(address, 0);
}
public ServerThread(ServerHandler server, String ip) throws Exception {
this(server, ip, 1024, 0);
}
public void run() {
while(true) {
try {
socket = dataSocket.accept();
socket.setKeepAlive(true);
socket.setSendBufferSize(megabyte);
socket.setSendBufferSize(megabyte);
socket.setTcpNoDelay(true);
socket.setReuseAddress(true);
InetSocketAddress clientAddress = new InetSocketAddress(socket.getInetAddress(), socket.getPort());
System.out.println("Starting");
if(getClients().size() > 0) {
for(Client c : getClients()) {
if(clientAddress != c.socket.getLocalSocketAddress()) {
Client client = new Client(socket, clientAddress);
getClients().add(client);
client.start();
System.out.println("Added new client!");
break;
}
}
} else {
Client client = new Client(socket, clientAddress);
getClients().add(client);
client.start();
System.out.println("Added new client!");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public synchronized void sendData(byte[] data, InetAddress IPaddress, int port) {
if(this.getClient(new InetSocketAddress(IPaddress, port)) != null) {
this.getClient(new InetSocketAddress(IPaddress, port)).sendData(data);
}
}
public void serverShutdown() {
try {
this.dataSocket.close();
if(this.socket != null) this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public int getClientIndex(InetSocketAddress address) {
int index = 0;
for(Client c : getClients()) {
if(c.socket.getRemoteSocketAddress().equals(address)) {
break;
}
index++;
}
System.out.println("Getting client index...");
return index;
}
public synchronized ArrayList<Client> getClients() {
return this.clients;
}
private Client getClient(InetSocketAddress address) {
for(Client c : getClients()) {
if(c.socket.getRemoteSocketAddress().equals(address)) {
return c;
}
}
return null;
}
public class Client extends Thread {
DataInputStream in;
DataOutputStream out;
Socket socket;
public Client(Socket sock, InetSocketAddress IPaddress) {
try {
socket = sock;
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(true) {
try {
byte[] data = new byte[in.readInt() - 4];
in.read(data);
server.parsePacket(data, socket.getInetAddress(), socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void sendData(byte[] data) {
try {
out.writeInt(data.length + 4);
out.write(data);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
如果有人可以提供帮助,我将不胜感激。 -关于用户.....
当两台计算机位于同一LAN上时,端口转发不起作用。 原因如下:
客户端将数据包发送到服务器的WAN地址。 它去路由器。 (因为局域网上的计算机使用路由器访问任何WAN地址。)
路由器端口将数据包转发到服务器的LAN地址。 源IP地址未更改,它仍然是客户端的LAN地址。 (这就是端口转发的功能。)
服务器通过将数据包发送到它看到的地址作为接收到的数据包的源地址(客户端的LAN地址)来接受TCP连接。 而且,当然,它为他们提供了唯一的源IP地址,即LAN地址。
从服务器发送到客户端的LAN地址的数据包直接进入客户端,路由器没有机会对其进行NAT,因为它们被发送到客户端的LAN地址。 (这是问题的出处。如果客户端位于另一个网络上,则数据包将到达路由器,因为这是服务器到达其他网络的方式。)
客户端从服务器的LAN地址接收数据包,但由于它希望从服务器的WAN地址获得数据包(因为这是它向其发送数据的地址),因此连接无法正常工作。
如果要从LAN上的其他计算机连接到服务器,则必须连接到服务器的LAN地址或使用某种形式的双NAT,例如发夹式NAT-端口转发将不起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.