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.