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

时间:2013-12-21 09:19:15

标签: java networking tcp client nat

我最近开始制作2D游戏,2天前开始制作tcp服务器,现在我的所有其他问题都已修复,我想解决一下这样一个事实:客户端只能连接到服务器在同一台设备上并使用设备静态IP,虽然它无法使用我的WAN IP地址连接,我有端口转发,我已经检查了许多端口检查器网站,他们都可以看到我的服务器,我的防火墙也被禁用,但客户端无法使用wan ip看到服务器,我在同一个端口上制作了一个矿工服务器(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();
            }
        }
    }
}

如果有人可以提供帮助,我会非常感激。 -问候 用户.....

1 个答案:

答案 0 :(得分:0)

当两台计算机位于同一LAN上时,端口转发不起作用。原因如下:

  1. 客户端将数据包发送到服务器的WAN地址。它去了路由器。 (因为LAN上的计算机使用路由器到达任何WAN地址。)

  2. 路由器端口将数据包转发到服务器的LAN地址。源IP地址不会更改,它仍然是客户端的LAN地址。 (这就是端口转发的作用。)

  3. 服务器接受TCP连接,方法是将数据包发送到它看到的地址,作为收到的数据包的源地址 - 客户端的LAN地址。当然,它为它们提供了唯一的源IP地址,它是LAN地址。

  4. 从服务器发送到客户端的LAN地址的数据包直接进入客户端,路由器没有机会对它们进行NAT,因为它们被发送到客户端的LAN地址。 (这里出现问题。如果客户端已经在另一个网络上,那么数据包就会转到路由器,因为这就是服务器到达其他网络的方式。)

  5. 客户端收到来自服

    如果要从LAN上的其他计算机连接到服务器,则必须连接到服务器的LAN地址或使用某种形式的双NAT,例如发夹NAT - 端口转发将无法正常工作。