Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何修复';服务器发送数据的速度快于客户端,服务器冻结';_Java_Sockets_Networking_Tcp - Fatal编程技术网

Java 如何修复';服务器发送数据的速度快于客户端,服务器冻结';

Java 如何修复';服务器发送数据的速度快于客户端,服务器冻结';,java,sockets,networking,tcp,Java,Sockets,Networking,Tcp,我正在使用java服务器在GameMaker Studio制作的游戏中促进在线多人游戏,玩家将向java服务器发送数据,java服务器将处理数据并将数据发送给玩家。问题在于,当网速较慢的玩家无法处理发送给它的数据量时,会导致服务器冻结所有玩家(服务器将不再处理其他玩家发送的任何数据) 我使用NetLimiter模拟了互联网的慢速,将一台笔记本电脑的下载速度设置为5 kb/s,同时在其他笔记本电脑上保持适当的速度。我曾尝试从java服务器向客户机发送ACK数据包,如果它在1秒内没有响应,将不会向该

我正在使用java服务器在GameMaker Studio制作的游戏中促进在线多人游戏,玩家将向java服务器发送数据,java服务器将处理数据并将数据发送给玩家。问题在于,当网速较慢的玩家无法处理发送给它的数据量时,会导致服务器冻结所有玩家(服务器将不再处理其他玩家发送的任何数据)

我使用NetLimiter模拟了互联网的慢速,将一台笔记本电脑的下载速度设置为5 kb/s,同时在其他笔记本电脑上保持适当的速度。我曾尝试从java服务器向客户机发送ACK数据包,如果它在1秒内没有响应,将不会向该客户机发送更多数据(最终客户机将被踢出)。这降低了冻结服务器的机会,但这种情况偶尔也会发生

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

}
如果发送的数据超过一个客户机可以处理的数量,那么服务器也将冻结所有其他客户机的数据

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

如果您能告诉我如何以正确的方式实现
ExecutorService
,那就太好了。

如果客户端处理延迟无关紧要,那么这一部分应该在每个客户端的不同流执行中完成:

for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) { 
        thread2.out_.print(msg);
        thread2.out_.flush();            
}
例如:

for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) { 
      if (thread2 != this) {
            new Thread(()-> {   
                                thread2.out_.print(msg);
                                thread2.out_.flush();
                            })
                      .start(); 
        }
}

请注意,创建线程是有成本的。使用
ExecutorService
可能是一个更好的主意。

谢谢。我试过上面的代码,但它没有解决服务器冻结的问题。我将尝试“ExecutorService”,希望这将是解决方案。我已尝试添加ExecutorService,但我一定是做错了什么:请参阅我问题的编辑。如果您能告诉我如何以正确的方式实现它,这将非常有帮助。
ExecutorService
不是“最佳”解决方案。它“只是”通过这个API处理较低级别的事情。我认为,要解决这个问题,你应该添加一些特定的痕迹,以指示它冻结的确切位置。
for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) { 
        thread2.out_.print(msg);
        thread2.out_.flush();            
}
for (final ClientThread thread2 : this.server_.ipToClientThread_.values()) { 
      if (thread2 != this) {
            new Thread(()-> {   
                                thread2.out_.print(msg);
                                thread2.out_.flush();
                            })
                      .start(); 
        }
}