2013-12-21 83 views
0

我最近开始制作2D java游戏,并在2天前开始制作一个tcp服务器,现在我所有的其他问题都已修复,我想解决这个事实,即客户端可以只有连接到服务器,当它在同一设备上,并使用设备的静态IP,虽然它不能连接使用我的WAN IP地址,我有端口转发,我检查了很多端口检查器网站,他们都可以看到我的服务器,我的防火墙也被禁用,但客户端无法看到使用wan ip的服务器,我在同一个端口上创建了一个minecraft服务器(我的世界服务器也是tcp),其他人可以使用我的wan ip连接。当客户端尝试使用我的wan ip进行连接时,它会发出Connection Refused异常。我究竟做错了什么?Java TCP客户端 - 服务器NAT连接拒绝

客户端(无法连接到服务器通过NAT):

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

我真的很感激,如果有人可以帮助:

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

服务器(可以通过一切,但客户可以看到) 。 -Regards 用户.....

回答

0

当两台机器都在同一个LAN上时,端口转发不起作用。原因如下:

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

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

  3. 服务器通过将数据包发送到它看到的地址作为它接收数据包的源地址(客户端的LAN地址)来接受TCP连接。当然,它给了它唯一的源IP地址,它是LAN地址。

  4. 从服务器发送到客户端LAN地址的数据包直接发送到客户端,路由器没有机会将它们NAT,因为它们被发送到客户端的LAN地址。 (如果客户端在另一个网络上,则数据包将被发送到路由器,因为这是服务器到达其他网络的方式)。

  5. 客户端从服务器的LAN地址接收数据包,但它期望从服务器的广域网地址发送数据包(因为这是它发送给它的),所以连接无法工作。

如果你想连接到其他设备在局域网上的服务器,您必须将其连接到服务器的局域网地址,或使用某种形式的双NAT如发夹的NAT - 端口转发将无法正常工作。

+0

我让我的朋友从他们的电脑上测试它,但它没有工作 – marko5049

+0

“它没有工作”是什么意思?“TCP连接是否完成?他们是否收到错误消息? –

+0

客户端抛出一个连接在尝试通过我的公共wan ip进行连接时拒绝异常 – marko5049

相关问题