Как преобразовать классический многопоточный сервер в неблокирующий сервер java.nio? - PullRequest
0 голосов
/ 21 апреля 2019

Я хочу преобразовать свой текущий многопоточный блокирующий сервер в неблокирующий сервер.Сервер используется в качестве сервера онлайн-игр (TCP) и обрабатывает данные от нескольких клиентов / игроков.Я следовал нескольким учебникам, показывающим, как сделать неблокирующий эхо-сервер, однако я все еще не знаю, как преобразовать мой текущий блокирующий сервер в неблокирующий сервер.

Мой текущий сервер в основном работает так:Файл main.java принимает новые клиентские подключения и создает новый поток (ClientThread.java) для каждого подключения.ServerInformation.java создает новый игровой сервер, к которому могут присоединиться другие клиенты.

Мой текущий многопоточный блокирующий сервер создает новый поток для каждого клиентского соединения, возможно ли это для неблокирующего сервера, потому что я неиначе знаете, что делать с файлом ClientThread.java.

Было бы замечательно, если бы кто-нибудь мог предоставить пример, учебное пособие или решение для кода.

Main.java

import java.net.Socket;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.io.IOException;
import java.util.HashMap;
import java.net.ServerSocket;
import java.net.SocketTimeoutException;

public class Main
{
    static ServerSocket serverSocket_;
    static HashMap<String, ServerInformation> servers_;
    static int verboseLevel_;
    static int threadTimeout_;
    static int masterPort_;
    static int serverNumber_;
    static int socketTimeOut_;

    static {
        Main.serverSocket_ = null;
        Main.servers_ = new HashMap<String, ServerInformation>();
        Main.verboseLevel_ = 5;
        Main.threadTimeout_ = 10;
        Main.masterPort_ = 6510;
        Main.serverNumber_ = 1;
        Main.socketTimeOut_ = 6000;
    }

    public static void main(final String[] args) {
        try {
            setupServerAndCleanup(Main.masterPort_);
            while (true) {
                handleIncomingConnection();
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    static void setupServerAndCleanup(final int port) throws IOException {
        (Main.serverSocket_ = new ServerSocket()).setReuseAddress(true);
        Main.serverSocket_.bind(new InetSocketAddress(Main.masterPort_));
        System.out.println("Server socket up and running on port " + Main.masterPort_);
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                if (Main.serverSocket_ != null) {
                    try {
                        Main.serverSocket_.close();
                        System.out.println("Server socket closed, port released");
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }));
    }

    static void handleIncomingConnection() throws IOException {
        final Socket clientSocket = Main.serverSocket_.accept();
        clientSocket.setSoTimeout(Main.socketTimeOut_);
        final ClientThread client = new ClientThread(clientSocket);
        client.start();
    }

}

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;
    import java.net.SocketTimeoutException;

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

                    final String tempInputLine;
                    if(((tempInputLine = this.in_.readLine()) == null )){
                        this.terminateThread(); //end thread                        
                        return;             
                    }
                    else
                    {                   
                        lastActionTime = System.currentTimeMillis();                    
                        final String inputLine = tempInputLine.trim();
                        if (ClientThread.numberPattern.matcher(inputLine).matches()){
                        final int val = Integer.parseInt(inputLine);
                        switch (val) {
                          case 1: { //send data to other players
                                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 2: { //remove game server
                                //this.logDebugMessage(1, "A game server has been deleted, ip: " + ipServer);
                                Main.servers_.remove(this.server_.ip_);
                                this.serverIp_ = null;
                                for (final ClientThread thread : this.server_.ipToClientThread_.values()) {
                                    thread.prepareTermination_ = true;
                                }
                                this.terminateThread();
                                return;
                            }
                            case 3: { //connect new client
                                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");
                                   this.out_.print("*" + 1 + "|" + 1 + "~" + "|");
                                   this.out_.flush();                                   
                                break;
                                }
                                this.server_ = info;
                                this.server_.ipToClientThread_.put(ipClient, this);
                                this.logDebugMessage(1, "Connection success");
                                this.logDebugMessage(5,"Map: " + this.server_.ipToClientThread_);
                                    this.out_.print("*" + 1 + "|" + 2 + "~" + "|");
                                    this.out_.flush();
                                break;
                            }         
                            case 4: { //disconnect client
                                final String ipClient = this.in_.readLine().trim();
                                this.server_.ipToClientThread_.remove(ipClient);
                                this.logDebugMessage(1, String.valueOf(ipClient) + " disconnected from the server at " + this.server_.ip_);
                                this.serverIp_ = null;
                                this.terminateThread();
                                return;
                            }                   

                            case 5: { //host create new game
                                if (Main.serverNumber_ > 1000000) {
                                Main.serverNumber_ = 10;    
                                }
                                Main.serverNumber_ += 1;                                
                                final String ipServer = Integer.toString(Main.serverNumber_); //unique server number
                                final String ipHost =  this.in_.readLine().trim(); //host 
                                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
                                final String servervar8 = this.in_.readLine().trim(); //Game server
                                final long servervar9 = System.currentTimeMillis(); //server creation time
                                //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, servervar8, servervar9, ipHost, ipServer, this.clientSocket_, this.out_, this.in_);
                                gameServer.description_ = description;
                                gameServer.ipToClientThread_.put(ipHost, 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 (SocketTimeoutException e) {
            e.printStackTrace();
            try {
                this.terminateThread();
            }
            catch (IOException e2) {
                e2.printStackTrace();
            }
        }
        catch (IOException e3) {
            e3.printStackTrace();
            try {
                this.terminateThread();
            }
            catch (IOException e4) {
                e4.printStackTrace();
            }
        }
    }

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

    //terminate thread
    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;
        }
    }
}

ServerInformation.java

import java.util.HashMap;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ServerInformation
{
    public String name_; //Server name
    public String description_; //class
    public String servervar1_; //max players
    public long servervar2_; //server last update
    public String servervar3_; //current lap
    public String servervar4_; //total laps
    public String servervar5_; //status
    public String servervar6_; //password
    public String servervar7_;  //online version    
    public String servervar8_;  //game server   
    public long servervar9_;    //server creation time      
    public String ipHost_; //ip host
    public String ip_; //unique id server
    public Socket socket_;
    PrintWriter out_;
    BufferedReader in_;
    HashMap<String, ClientThread> ipToClientThread_;

    public ServerInformation(final String name, final String servervar1, final String servervar3, final String servervar4, final String servervar5, final String servervar6, final String servervar7, final String servervar8, final long servervar9, final String ipHost, final String ip, final Socket socket, final PrintWriter out, final BufferedReader in) {
        this.name_ = name;
        this.description_ = ""; //class
        this.servervar1_ = servervar1; //max players
        this.servervar2_ = System.currentTimeMillis(); //server last update
        this.servervar3_ = servervar3; //current lap
        this.servervar4_ = servervar4; //total laps
        this.servervar5_ = servervar5; //status
        this.servervar6_ = servervar6; //password
        this.servervar7_ = servervar7; //online version 
        this.servervar8_ = servervar8; //game server        
        this.servervar9_ = servervar9; //server creation time           
        this.ipHost_ = ipHost;
        this.ip_ = ip;
        this.socket_ = socket;
        this.out_ = out;
        this.in_ = in;
        this.ipToClientThread_ = new HashMap<String, ClientThread>();
    }
}
...