简体   繁体   English

Java TCP客户端-服务器NAT连接被拒绝

[英]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. 我最近开始制作2D Java游戏,并在2天前开始制作tcp服务器,现在所有其他问题都已解决,我想解决一个事实,即客户端只能在同一服务器上连接到服务器设备和使用设备静态ip的设备,尽管它无法使用我的wan ip地址进行连接,但是我已转发了端口,并在许多端口检查器网站上进行了检查,它们都可以看到我的服务器,我的防火墙也被禁用,但是客户端可以没有看到使用wan ip的服务器,我在同一端口上制作了一个minecraft服务器(Minecraft服务器也是tcp),其他服务器则可以使用wan ip进行连接。 When a client does try to connect using my wan ip, it gives a Connection Refused exception. 当客户端尝试使用我的wan ip进行连接时,它会给出Connection Refused异常。 What am i doing wrong? 我究竟做错了什么?

Client (Can't connect to server over nat): 客户端(无法通过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. 当两台计算机位于同一LAN上时,端口转发不起作用。 Here's why: 原因如下:

  1. The client sends a packet to the server's WAN address. 客户端将数据包发送到服务器的WAN地址。 It goes to the router. 它去路由器。 (Because machines on a LAN use the router to reach any WAN address.) (因为局域网上的计算机使用路由器访问任何WAN地址。)

  2. The router port forwards the packet to the server's LAN address. 路由器端口将数据包转发到服务器的LAN地址。 The source IP address is not changed, it's still the client's LAN address. 源IP地址未更改,它仍然是客户端的LAN地址。 (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. 服务器通过将数据包发送到它看到的地址作为接收到的数据包的源地址(客户端的LAN地址)来接受TCP连接。 And, of course it gives them the only source IP address it can, it's LAN address. 而且,当然,它为他们提供了唯一的源IP地址,即LAN地址。

  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. 从服务器发送到客户端的LAN地址的数据包直接进入客户端,路由器没有机会对其进行NAT,因为它们被发送到客户端的LAN地址。 (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. 客户端从服务器的LAN地址接收数据包,但由于它希望从服务器的WAN地址获得数据包(因为这是它向其发送数据的地址),因此连接无法正常工作。

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. 如果要从LAN上的其他计算机连接到服务器,则必须连接到服务器的LAN地址或使用某种形式的双NAT,例如发夹式NAT-端口转发将不起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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