0

I have a multithreaded tcp server, that handles multiple clients. Each client has its thread on the serverside that keeps the socket connection. Everything theoretically works fine for many minutes, but at rare occasions, while having multiple clients connected, the following happens: One of the clients sends a tcp packet to the server and the serverside read times out. I have found many questions, that tackle read timeouts on the clientside, but in my case, this never happens. In my case, the server times out on a read when receiving a packet from a client. My question is, why and how can this happen and what can I do to handle this problem?

here is my server listener:

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

}

here is my server thread that hold each single connection:

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

}

And here is my client:

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

}

I hope to find out more about this issue, please help! :)

EDIT: It may be important to say, that while my program is running, it can occur, that there are no tcp packets sent over a longer period of time. The timeout always happens, when i dont send any packets for at least 20 or 30 minutes and then when i send one again, another client times out.

2
  • There is nothing random about read timeouts. The peer didn't send anything within the timeout period. Either it's too short or there is something wrong with the peer, or the network. Commented Aug 24, 2017 at 11:33
  • But isnt the default timeout of tcp connections set to infinite? Peer and network are fine. Commented Aug 24, 2017 at 11:34

1 Answer 1

1

As it turned out, tcp sockets, that are not used longer than a certain amount of time will be kind of destroyed by peers and therefore lose their connection. I solved my issue, by sending a nearly empty tcp packet every minute to make it clear to all programs and services, that these sockets are alive!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.