2017-08-24 2 views
0

Ich habe einen Multithread-TCP-Server, der mehrere Clients verarbeitet. Jeder Client hat seinen Thread auf der Serverseite, der die Socket-Verbindung aufrechterhält. Alles funktioniert theoretisch für viele Minuten, aber in seltenen Fällen, während mehrere Clients verbunden sind, geschieht Folgendes: Einer der Clients sendet ein TCP-Paket an den Server und das Server-Side-Timeout. Ich habe viele Fragen gefunden, die Lese-Timeouts auf der Client-Seite angehen, aber in meinem Fall passiert das nie. In meinem Fall läuft der Server beim Lesen eines Pakets von einem Client ab. Meine Frage ist, warum und wie kann das passieren und was kann ich tun, um mit diesem Problem umzugehen?Multithread-Server nach dem Zufallsprinzip wirft java.net.SocketTimeoutException: Zeitüberschreitung gelesen

hier ist mein Server Zuhörer:

public class GameServerTCP extends Thread { 

//TCP 
private ServerSocket serverSocket; 
public Server server; 
public int amountOfTCPConnections = 0; 

ClassLoader classLoader = getClass().getClassLoader(); 
File myFile = new File(classLoader.getResource("Sprites/sprite_sheet.png").getFile()); 

public GameServerTCP(Server game) { 
    this.server = game; 

    //TCP 
    try { 
     serverSocket = new ServerSocket(6336); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

public void run() { 
    while(true) { 
     //TCP 
     Socket socket = null; 

     try { 
      socket = serverSocket.accept(); 
      Toolkit.getDefaultToolkit().beep(); 
      System.out.println(socket.getRemoteSocketAddress() + " has connected to server."); 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
     } 

     new TCPConnection(socket, this); 
     amountOfTCPConnections++; 

     if (amountOfTCPConnections > 500) { 
      System.err.println("Too many clients error! (unsolved)"); 
      server.frame.dispatchEvent(new WindowEvent(server.frame, WindowEvent.WINDOW_CLOSING)); 
     } 
    } 
} 

}

hier Thread meinem Server ist, die jede einzelne Verbindung halten:

public class TCPConnection implements Runnable { 

Socket socket; 
private Thread thread; 
private boolean isRunning = false; 
public GameServerTCP serverTCP; 
private String gamename = "-1"; 
public String username; 

/** 
* This is the future! 
* Contains an exact imprint of the player of client side. 
* Cheats can be detected here. 
*/ 
private PlayerMP playerMP; 

String clientSentence; 

TCPConnection(Socket socket, GameServerTCP serverTCP) { 
    this.socket = socket; 
    this.serverTCP = serverTCP; 
    isRunning = true; 
    thread = new Thread(this); 
    thread.start(); 
} 

public synchronized void closeConnection() { 
    if (MasterConnections.connectionsTCP.containsKey(getUniqueConnectionIdentifier())) MasterConnections.connectionsTCP.remove(getUniqueConnectionIdentifier()); 
    if (this.username != null && MasterConnections.currentlyLoggedOnAccounts.contains(this.username)) MasterConnections.currentlyLoggedOnAccounts.remove(this.username); 

    if (this.gamename != null && serverTCP.server.games.containsKey(this.gamename)) { 
     Level game = serverTCP.server.games.get(this.gamename); 
     for (String p : game.playersInLevel) { 
      if (p.equals(getUniqueConnectionIdentifier())) { 
       game.playersInLevel.remove(p); 
       System.out.println(this.username + " has been been removed from game " + this.gamename + "."); 
      } 
     } 

     PacketTCP02LeaveGame tellOthersPacket = new PacketTCP02LeaveGame(this.gamename, this.username); 
     game.writeDataTCPToAllPlayersInThisLevel(tellOthersPacket); 
    } 

    try { 
     this.socket.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    System.out.println(socket.getRemoteSocketAddress() + " has been disconnected from server."); 
    this.serverTCP.amountOfTCPConnections--; 
    this.stop(); 
} 

public String getUniqueConnectionIdentifier() { 
    return socket.getInetAddress() + ":" + socket.getPort(); 
} 

public String generateUniqueUDPConnectionIdentifier(InetAddress inetAddess, int udpPort) { 
    System.out.println("uuc created: "); 
    System.out.println(inetAddess + "/" + udpPort); 
    return inetAddess + ":" + udpPort; 
} 

public void run() { 
    //version check first 
    PacketTCP00VersionCheck packetVersionCheck = new PacketTCP00VersionCheck(serverTCP.server.getVersion()); 

    if (MasterConnections.connectionsTCP.containsKey(getUniqueConnectionIdentifier())) { 
     this.closeConnection(); 
    } 
    else { 
     MasterConnections.connectionsTCP.put(getUniqueConnectionIdentifier(), this); 
     packetVersionCheck.writeData(this); 
    } 

    BufferedReader inFromClient; 
    try { 
     inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
    } catch (IOException e1) { 
     e1.printStackTrace(); 
     closeConnection(); 
     return; 
    } 

    while(isRunning) { 
     try { 
      clientSentence = inFromClient.readLine(); 
      if (clientSentence == null) { 
       inFromClient.close(); 
       closeConnection(); 
      } 
      else { 
       System.out.println("tcprec -> " + (new Date(System.currentTimeMillis())) + " -> " + this.username + " -> " + clientSentence); 
       this.parsePacket(clientSentence.getBytes()); 
      } 
     } 
     catch (SocketTimeoutException ste) { 
      /** 
      * TODO: 
      */ 
      ste.printStackTrace(); 
      System.err.println("YOU CAN DO SOMETHING HERE!!!!!!!"); 
      closeConnection(); 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
      closeConnection(); 
     } 
    } 
} 

public void stop() { 
    isRunning = false; 
    try { 
     thread.join(); 
    } 
    catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

}

Und hier ist mein Kunde :

public class GameClientTCP extends Thread { 

public String gamestate = "logged out"; 

private Game game; 
public Socket tcpSocket; 
public boolean isRunning = false; 
private String serverSentence; 
public boolean hasBeenStarted = false; 

public int boundUDPPort = -1; 

public static String[] characters = new String[5]; 
public static boolean charactersAreLoaded = false; 

private PrintWriter toServer; 

public GameClientTCP(Game game, String ipAddress) { 
    this.game = game; 
} 

public boolean tryConnect() { 
    try { 
     tcpSocket = new Socket(); 
     tcpSocket.connect(new InetSocketAddress(Settings.SERVER_ADDRESS, 6336), 1000); 
     System.out.println("Just connected to " + tcpSocket.getRemoteSocketAddress()); 

     game.getSocketClientUDP().prepareBeforeStart(); 
     game.getSocketClientUDP().start(); 

     return true; 
    } catch (UnknownHostException e1) { 
     try { 
      tcpSocket.close(); 
     } catch (IOException e) { 
      GameError.appendToErrorLog(e); 
      return false; 
     } 
     return false; 
    } catch (IOException e1) { 
     try { 
      tcpSocket.close(); 
     } catch (IOException e) { 
      GameError.appendToErrorLog(e); 
      return false; 
     } 
     GameError.appendToErrorLog(e1); 
     return false; 
    } 
} 

public void run() { 
    BufferedReader fromServer; 
    try { 
     fromServer = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream())); 
     toServer = new PrintWriter(tcpSocket.getOutputStream(),true); 
    } catch (IOException e1) { 
     GameError.appendToErrorLog(e1); 
     return; 
    } 

    while(isRunning) { 
     try { 
      serverSentence = fromServer.readLine(); 
      //System.out.println("Received: " + serverSentence); 
      if (serverSentence != null) this.parsePacket(serverSentence.getBytes()); 
     } 
     catch(UnknownHostException ex) { 
      GameError.appendToErrorLog(ex); 
     } 
     catch(IOException e){ 
      GameError.appendToErrorLog(e); 
     } 
     catch(Exception e) { 
      GameError.appendToErrorLog(e); 
     } 
    } 
} 

public void sendMessageToServer(String message) { 
    try { 
     toServer.println(message); 
     toServer.flush(); 
    } 
    catch (Exception e) { 
     GameError.appendToErrorLog(e); 
     System.exit(-1); 
    } 
} 

}

Ich hoffe, mehr über dieses Thema zu erfahren, wenden Sie sich bitte helfen! :)

EDIT: Es kann wichtig sein zu sagen, dass, während mein Programm läuft, kann es vorkommen, dass es keine TCP-Pakete über einen längeren Zeitraum gesendet werden. Die Zeitüberschreitung tritt immer auf, wenn ich keine Pakete für mindestens 20 oder 30 Minuten sende und dann, wenn ich einen erneut sende, ein anderer Client das Zeitlimit überschreitet.

+0

Es gibt keine zufälligen Lese-Timeouts. Der Peer hat innerhalb des Timeout-Zeitraums nichts gesendet. Entweder ist es zu kurz oder etwas stimmt nicht mit dem Peer oder dem Netzwerk. – EJP

+0

Aber ist das Standard-Timeout von TCP-Verbindungen nicht auf unendlich eingestellt? Peer und Netzwerk sind in Ordnung. – Madness

Antwort

0

Wie sich herausstellte, werden TCP-Sockets, die nicht länger als eine bestimmte Zeit verwendet werden, von Peers zerstört und verlieren daher ihre Verbindung. Ich löste mein Problem, indem ich jede Minute ein fast leeres TCP-Paket sendete, um allen Programmen und Diensten zu verdeutlichen, dass diese Sockets am Leben sind!

Verwandte Themen