Java-сервер Digital Ocean продолжает падать: java.net.SocketException: сброс соединения - PullRequest
0 голосов
/ 10 июня 2018

Я использую сервер Digital Ocean, чтобы облегчить многопользовательскую онлайн-игру в моем ПКСервер представляет собой небольшое приложение, написанное на Java.Проблема в том, что сервер периодически отключается и автоматически перезагружается через 15 минут.Я обновлял сервер пару раз, но, похоже, это не имело никакого значения, наконец-то я использую оптимизированную для ЦП каплю с 4 ГБ памяти, 2 виртуальными ЦП и 20 ГБ диском.Я не совсем уверен, но казалось, что сервер отключился, когда в сети было около 15 человек, но иногда в сети было столько же людей (или больше), и не происходило сбоев.Это происходит примерно 1-2 раза в день, когда большинство людей находятся в сети.

Графики:

-1 минута после сбоя сервера (19:29): https://imgur.com/a/Asit3O6

-Сервер выключен на 12 минут (19:41): https://imgur.com/a/ulIgTau

-Сервер снова включен (7:50 вечера): https://imgur.com/a/gMOn4Jf

-Сервер снова включен на 28 минут(8:18 вечера): https://imgur.com/a/lA8dufN

Консоль:

- После сбоя сервера (7:39 Pm): https://imgur.com/a/h7r701H отображается:

java.net.SocketException: Connection reset

-После того, как сервер снова подключен (7:50 вечера): https://imgur.com/a/l85FYFw

Единственное, что я узнаю, это файл ClientThread.java, который является одним из 3 файлов Java, входящих в состав сервера.Я также должен сказать, что мой опыт работы с Java очень прост и что кто-то другой создал файлы java-сервера (которых нет в наличии), но я понимаю большую часть этого и сам внес небольшие изменения.

Любая причинапочему иногда происходит сбой этого сервера?

Вот файл ClientThread.java:

import java.util.Iterator;
import java.io.IOException;
import java.io.Reader;
import java.io.InputStreamReader;
import java.util.regex.Pattern;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.net.Socket;

// 
// Decompiled by Procyon v0.5.30
// 

public class ClientThread extends Thread
{
    Socket clientSocket_;
    String clientIp_;
    String serverIp_;
    ServerInformation server_;
    PrintWriter out_;
    BufferedReader in_;
    boolean prepareTermination_;
    boolean terminated_;
    private static final Pattern numberPattern;

    static {
        numberPattern = Pattern.compile("\\d+");
    }

    public ClientThread(final Socket sock) {
        this.clientSocket_ = sock;
        this.clientIp_ = this.clientSocket_.getRemoteSocketAddress().toString();
        this.serverIp_ = null;
        this.server_ = null;
        this.prepareTermination_ = false;
        this.terminated_ = false;
    }

    @Override
    public void run() {
        try {
            //this.logDebugMessage(2, "Client socket accepted, ip: " + this.clientIp_);
            this.out_ = new PrintWriter(this.clientSocket_.getOutputStream(), true);
            this.in_ = new BufferedReader(new InputStreamReader(this.clientSocket_.getInputStream()));
            long lastActionTime = System.currentTimeMillis();
            while (true) {
                if (this.in_.ready() || System.currentTimeMillis() - lastActionTime >= 1000 * Main.threadTimeout_) {
                    if (System.currentTimeMillis() - lastActionTime >= 1000 * Main.threadTimeout_) {
                        //this.logDebugMessage(3, "Thread was killed due to prolonged inactivity (" + Main.threadTimeout_ + " seconds)");
                        this.terminateThread();
                        return;
                    }
                    lastActionTime = System.currentTimeMillis();
                    final String inputLine = this.in_.readLine().trim();
                    if (ClientThread.numberPattern.matcher(inputLine).matches()) {
                        final int val = Integer.parseInt(inputLine);
                        switch (val) {
                            case 111: { //send to client fast b
                                final StringBuilder msg = new StringBuilder();
                                    msg.append(String.valueOf(this.in_.readLine().trim()));
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {
                                    if (thread2 != this) {
                                        thread2.out_.print(msg);
                                        thread2.out_.flush();
                                    }
                                }
                                break;
                            }                           
                            case 110: { //send to ip fast
                                final String ip = this.in_.readLine().trim();
                                final ClientThread target = this.server_.ipToClientThread_.getOrDefault(ip, null);
                                if (target != null) {
                                    target.out_.print(this.in_.readLine().trim());
                                    target.out_.flush();
                                    break;
                                }                               
                            }                               
                            case 109: { //send to server fast
                                this.server_.out_.print(this.in_.readLine().trim());
                                this.server_.out_.flush();
                                break;
                            }                               
                            case 108: { //send to all fast
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {          
                                        thread2.out_.print(this.in_.readLine().trim());
                                        thread2.out_.flush();
                                }
                                break;
                            }                           
                            case 107: { //send to others fast
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {
                                    if (thread2 != this) {
                                        thread2.out_.print(this.in_.readLine().trim());
                                        thread2.out_.flush();
                                    }
                                }
                                break;
                            }                           
                            case 106: {
                                this.server_.description_ = this.in_.readLine().trim(); //class                             
                                break;
                            }                                                           
                            case 105: {
                                this.out_.print("*" + 26 + "|" + this.server_.servervar3_ + "|" + this.server_.servervar4_ + "|" + this.server_.servervar5_ + "~" + "|");
                                this.out_.flush();
                                break;
                            }                               
                            case 104: {
                                this.server_.servervar5_ = this.in_.readLine().trim(); //status         
                                break;
                            }                                   
                            case 103: {
                                this.server_.servervar3_ = this.in_.readLine().trim(); //current lap                
                                break;
                            }                                       
                            case 102: {
                                this.server_.servervar3_ = this.in_.readLine().trim(); //current lap
                                this.server_.servervar4_ = this.in_.readLine().trim(); //total laps
                                this.server_.servervar5_ = this.in_.readLine().trim(); //status                     
                                break;
                            }                       
                            case 101: { //admin quit server
                                final String ipServer = this.in_.readLine().trim();
                                final ServerInformation info = Main.servers_.getOrDefault(ipServer, null);
                                this.server_ = info;                
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {
                                        thread2.out_.print("*" + 22 + "|" + -1 + "~" + "|");
                                        thread2.out_.flush();
                                }                                   
                                //this.logDebugMessage(1, "A game server has been deleted, ip: " + ipServer);
                                Main.servers_.remove(ipServer);                                                     
                                break;
                            }                           
                            case 100: { 
                                if (System.currentTimeMillis() - this.server_.servervar2_ >= 1000 * 20) { //clients check if server is still online
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {
                                        thread2.out_.print("*" + 22 + "|" + -1 + "~" + "|");
                                        thread2.out_.flush();          
                                }                                   
                                final String ipServer = this.server_.ip_;
                                //this.logDebugMessage(1, "A game server has been deleted, ip: " + ipServer);
                                Main.servers_.remove(ipServer);
                                }
                                break;
                            }                           
                            case 99: {
                                this.server_.servervar2_ = System.currentTimeMillis(); //send server last update
                                break;
                            }
                            case 98: {
                                final String ipServer = this.in_.readLine().trim();
                                //this.logDebugMessage(1, "A game server has been deleted, ip: " + ipServer);
                                Main.servers_.remove(ipServer);
                                this.serverIp_ = null;
                                for (final ClientThread thread : this.server_.ipToClientThread_.values()) {
                                    thread.prepareTermination_ = true;
                                }
                                this.terminateThread();
                                return;
                            }
                            case 96: {
                                final String ipServer = this.in_.readLine().trim();
                                final String ipClient = this.in_.readLine().trim(); 
                                //this.logDebugMessage(1, "A client wishes to connect to a server, client: " + ipClient + ", server: " + ipServer);
                                final ServerInformation info = Main.servers_.getOrDefault(ipServer, null);
                                if (info == null) {
                                    System.out.println("Connection to the server failed, no such server in the server list");
                                    out_.print("*" + 1 + "|" + 1 + "~" + "|");
                                    out_.flush();                                   
                                break;
                                }
                                this.server_ = info;
                                this.server_.ipToClientThread_.put(ipClient, this);
                                this.server_.numplayers_ += 1;
                                //this.logDebugMessage(1, "Connection success");
                                    out_.print("*" + 1 + "|" + 2 + "~" + "|");
                                    out_.flush();
                                break;
                            }
                            case 95: {
                                final String ipClient = this.in_.readLine().trim();
                                this.server_.ipToClientThread_.remove(this);
                                this.server_.numplayers_ -= 1;
                                //this.logDebugMessage(1, String.valueOf(ipClient) + " disconnected from the server at " + this.server_.ip_);
                                this.terminateThread();
                                return;
                            }
                            case 94: {
                                final int parseCount = Integer.parseInt(this.in_.readLine().trim());
                                final StringBuilder msg = new StringBuilder();
                                for (int i = 0; i < parseCount; ++i) {
                                    msg.append(String.valueOf(this.in_.readLine().trim()) + "|");
                                }
                                this.server_.out_.print(msg.toString());
                                this.server_.out_.flush();
                                //this.logDebugMessage(5, "Packet for server: '" + msg.toString() + "'");
                                break;
                            }
                            case 93: {
                                final int parseCount = Integer.parseInt(this.in_.readLine().trim());
                                final String ip = this.in_.readLine().trim();
                                final StringBuilder msg = new StringBuilder();
                                for (int i = 0; i < parseCount - 1; ++i) {
                                    msg.append(String.valueOf(this.in_.readLine().trim()) + "|");
                                }
                                final ClientThread target = this.server_.ipToClientThread_.getOrDefault(ip, null);
                                if (target != null) {
                                    target.out_.print(msg.toString());
                                    target.out_.flush();
                                    //this.logDebugMessage(5, "Packet for " + ip + ": '" + msg.toString() + "'");
                                    break;
                                }
                                //this.logDebugMessage(1, "Packet for " + ip + " failed to send (recipient not found)");
                                break;
                            }
                            case 92: {
                                final int parseCount = Integer.parseInt(this.in_.readLine().trim());
                                final StringBuilder msg = new StringBuilder();
                                for (int j = 0; j < parseCount; ++j) {
                                    msg.append(String.valueOf(this.in_.readLine().trim()) + "|");
                                }
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {
                                    thread2.out_.print(msg);
                                    thread2.out_.flush();
                                }
                                //this.logDebugMessage(5, "Packet for all: '" + msg.toString() + "'");
                                break;
                            }
                            case 91: {
                                final int parseCount = Integer.parseInt(this.in_.readLine().trim());
                                final StringBuilder msg = new StringBuilder();
                                for (int j = 0; j < parseCount; ++j) {
                                    msg.append(String.valueOf(this.in_.readLine().trim()) + "|");
                                }
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {
                                    if (thread2 != this) {
                                        thread2.out_.print(msg);
                                        thread2.out_.flush();
                                    }
                                }
                                //this.logDebugMessage(5, "Packet for others: '" + msg.toString() + "'");
                                break;
                            }
                            case 90: {
                                //this.logDebugMessage(2, "A socket has requested the advanced server list, server list size: " + Main.servers_.size());
                                if (Main.servers_.size()==0) {
                                    this.out_.print("*" + 0 + "|" + 0 + "|" + 0 + "|" + 0 + "|" + 0 + "|" + 0 + "|" + 0 + "~" + "|");   
                                } else {
                                for (final ServerInformation info2 : Main.servers_.values()) {
                                    this.out_.print("*" + String.valueOf(info2.name_) + "|" + info2.ip_ + "|" + info2.description_ + "|" + info2.servervar1_ + "|"  + info2.servervar2_ + "|"  + info2.servervar3_ + "|"  + info2.servervar4_ + "|"  + info2.servervar5_ + "|" + info2.numplayers_ + "|" + info2.ipToClientThread_.size() + "|"  + info2.servervar6_ + "|"  + info2.servervar7_ + "~" + "|");
                                if (System.currentTimeMillis() - info2.servervar2_ >= 1000 * 20) {
                                final String ipServer = info2.ip_;
                                final ServerInformation info = Main.servers_.getOrDefault(ipServer, null);
                                this.server_ = info;                
                                for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) {
                                        thread2.out_.print("*" + 22 + "|" + -1 + "~" + "|");
                                        thread2.out_.flush();
                                }                                   
                                //this.logDebugMessage(1, "A game server has been deleted, ip: " + ipServer);
                                Main.servers_.remove(ipServer);
                                }                                                           
                                }                               
                                }
                                this.out_.flush();
                                break;
                            }
                            case 89: {
                                final String ipServer = this.in_.readLine().trim();
                                final String name = this.in_.readLine().trim(); //Server name
                                final String description = this.in_.readLine().trim(); //class
                                final String servervar1 = this.in_.readLine().trim(); //max players
                                final String servervar3 = this.in_.readLine().trim(); //current lap
                                final String servervar4 = this.in_.readLine().trim(); //total laps
                                final String servervar5 = this.in_.readLine().trim(); //status
                                final String servervar6 = this.in_.readLine().trim(); //Password
                                final String servervar7 = this.in_.readLine().trim(); //Online version
                                //this.logDebugMessage(1, "A game server has been registered, ip: " + ipServer + ", name: " + name + ", description: " + description + ", servervar1: " + servervar1);
                                final ServerInformation gameServer = new ServerInformation(name, servervar1, servervar3, servervar4, servervar5, servervar6, servervar7, ipServer, this.clientSocket_, this.out_, this.in_);
                                gameServer.description_ = description;
                                gameServer.ipToClientThread_.put(ipServer, this);
                                this.server_ = gameServer;
                                Main.servers_.put(ipServer, gameServer);
                                this.serverIp_ = ipServer;
                                break;
                            }
                            default: {
                                //this.logDebugMessage(0, "Unrecognized case: '" + inputLine + "', " + val);
                                break;
                            }
                        }
                    }
                    else if (inputLine.length() > 0) {
                        //this.logDebugMessage(0, "Unformated '" + inputLine + "'");
                        if (this.server_ != null) {
                            this.server_.out_.print(inputLine);
                            this.server_.out_.flush();
                        }
                    }
                    if (this.prepareTermination_) {
                        this.terminateThread();
                        return;
                    }
                    continue;
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
            try {
                this.terminateThread();
            }
            catch (IOException e2) {
                e2.printStackTrace();
            }
        }
    }

    void logDebugMessage(final int requiredVerbose, final String msg) {
        if (Main.verboseLevel_ >= requiredVerbose) {
            System.out.println("[" + this.clientIp_ + "]  " + msg);
        }
    }

    void terminateThread() throws IOException {
        if (!this.terminated_) {
            if (this.serverIp_ != null) {
                Main.servers_.remove(this.serverIp_);
            }
            this.clientSocket_.close();
            this.in_.close();
            this.out_.close();
            //this.logDebugMessage(3, "Cleanup successful");
            this.terminated_ = true;
        }
    }
}

1 Ответ

0 голосов
/ 10 июня 2018

Согласно JavaDocs # ConcurrentModificationException :

Обратите внимание, что это исключение не всегда означает, что объект был одновременно изменен другим потоком.Если один поток выдает последовательность вызовов методов, которая нарушает контракт объекта, объект может вызвать это исключение.Например, если поток изменяет коллекцию напрямую, в то время как он выполняет итерацию по коллекции с помощью итератора, работающего без сбоев, итератор выдаст это исключение.

И вы удаляетеMain.servers_.remove(ipServer) при выполнении итерации в этой строке:

for (final ServerInformation info2 : Main.servers_.values())

Использование ConcurrentHashMap:

Map<String, String> myMap = new ConcurrentHashMap<String, String>();
myMap.put("1", "1");
myMap.put("2", "2");
myMap.put("3", "3");

Iterator<String> it1 = myMap.keySet().iterator();
while (it1.hasNext()) {
    String key = it1.next();
    System.out.println("Map Value:" + myMap.get(key));
    if (key.equals("1")) {
        myMap.remove("3");
        myMap.put("4", "4");
        myMap.put("5", "5");
    }
}

Вышеприведенный код может вернуть:

Map Value:1
Map Value:2
Map Value:4
Map Value:5

Редактировать: об сбросе соединения:

Кажется, ваш вход имеет значение null , поэтому он плохо отключается.Вы всегда должны обрабатывать проверку недействительности в readLine ().Вот так (измените свой код):

final String tempInputLine;

if((tempInputLine = this.in_.readLine()) == null ){
    //close
    this.terminateThread();
    return;
}
else{

    final String inputLine = tempInputLine.trim();
    if (ClientThread.numberPattern.matcher(inputLine).matches()){
        //...
    }
    //..
}
...