多线程服务器随机抛出java.net.SocketTimeoutException:读超时(Mult

2019-11-04 10:47发布

我有一个多线程的TCP服务器,用于处理多个客户端。 每个客户端具有对保持套接字连接的服务器端的线程。 理论上一切工作正常的许多分钟,但在极少数情况下,虽然具有多个客户端连接时,会发生以下情况:其中一个客户发送一个TCP数据包到服务器和服务器端读取超时。 我发现有很多问题,即滑车在客户方读超时,但对我来说,这永远不会发生。 在我的情况下,从客户端接收数据包时的服务器超时的读取。 我的问题是,为什么这怎么可能发生,我能做些什么来解决这个问题?

这里是我的服务器监听器:

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

}

这里要说的是保持每个单独的连接我的服务器线程:

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

}

这里是我的客户:

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

}

我希望能找到更多关于这个问题,请大家帮忙! :)

编辑:这可能是重要的说,我的程序运行时,可能会发生的,有送过来的较长一段时间没有TCP数据包。 超时总是会发生的,当我不发送任何数据包至少20或30分钟,然后当我再次发送一个,另一个客户超时。

Answer 1:

事实证明,TCP套接字,未超过一定的时间使用较长会有种被同行破坏并因此失去其连接。 我解决了我的问题,通过发送一个几乎空TCP数据包每分钟要清楚到所有程序和服务,这些插座还活着!



文章来源: Multithreaded server randomly throws java.net.SocketTimeoutException: Read timed out