2013-12-21 85 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

相關問題