简体   繁体   中英

Java TCP client-server NAT Connection Refused

I recently started making a 2D java game, and started making a tcp server 2 days ago, now that all my other issues are fixed, I would like to address the fact that the client can only connect to the server when it is on the same device and using the devices static ip, though it cannot connect using my wan ip address, I have port forwarded and I have checked on many port-checker websites and they all can see my server, my firewall is also disabled, yet the client can't see the server using the wan ip, I made a mine craft server on the same port (Minecraft servers are also tcp) and others were able to connect using my wan ip. When a client does try to connect using my wan ip, it gives a Connection Refused exception. What am i doing wrong?

Client (Can't connect to server over 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();
        }
    }
}

Server (Can be seen by everything but client):

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();
            }
        }
    }
}

I would really appreciate it if someone could help. -Regards user.....

Port forwarding does not work when both machines are on the same LAN. Here's why:

  1. The client sends a packet to the server's WAN address. It goes to the router. (Because machines on a LAN use the router to reach any WAN address.)

  2. The router port forwards the packet to the server's LAN address. The source IP address is not changed, it's still the client's LAN address. (That's what port forwarding does.)

  3. The server accepts the TCP connection by sending packets to the address it saw as the source address of the packets it received -- the client's LAN address. And, of course it gives them the only source IP address it can, it's LAN address.

  4. Packets sent from the server to the client's LAN address go directly to the client, the router has no opportunity to NAT them because they are sent to the client's LAN address. (Here's where things go awry. If the client had been on another network, the packets would have gone to the router, since that's how the server reaches other networks.)

  5. The client receives packets from the server's LAN address, but it was expecting packets from the server's WAN address (since that's what it sent them to), so the connection cannot work.

If you want to connect to the server from other machines on the LAN you must either connect to the server's LAN address or use some form of dual-NAT such as hairpin NAT -- port forwarding won't work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM