java Java中如何方便服务器线程和多个客户端线程之间的通信

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3849641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 03:40:13  来源:igfitidea点击:

How to facilitate communication between the server thread and the multiple client threads in Java

javamultithreadingsockets

提问by mixm

I'm trying to create a client server game using java sockets. I have a thread server which controls the logic of the game. I also have client threads that communicate with the server. I use multiple client handler threads to facilitate server-to-client communication. I use multiple threads to communicate with other client threads using sockets.

我正在尝试使用 Java 套接字创建客户端服务器游戏。我有一个控制游戏逻辑的线程服务器。我也有与服务器通信的客户端线程。我使用多个客户端处理程序线程来促进服务器到客户端的通信。我使用多个线程通过套接字与其他客户端线程进行通信。

Now, I have a problem on how to facilitate communication between the server thread and the multiple client threads. For example, should the server select the next player to play, how should it signal the client handler thread, and in turn communicate with the client thread through sockets?

现在,我有一个关于如何促进服务器线程和多个客户端线程之间的通信的问题。例如,服务器是否应该选择下一个播放器,它应该如何向客户端处理程序线程发送信号,然后通过套接字与客户端线程进行通信?

回答by Codemwnci

I have done this before in the following way. I have a Server socket

我以前通过以下方式做到了这一点。我有一个服务器套接字

    public Server(int port, int numPlayers) {
    game = new PRGameController(numPlayers);

    try {

        MessageOutput.info("Opening port on " + port);
        ServerSocket clientConnectorSocket = new ServerSocket(port);
        MessageOutput.info("Listening for connections");

        while (!game.isFull()) {
            // block until we get a connection from a client
            final Socket client = clientConnectorSocket.accept();
            MessageOutput.info("Client connected from " + client.getInetAddress());

            Runnable runnable = new Runnable() {
                public synchronized void run() {
                    PRGamePlayer player = new PRGamePlayer(client, game);
                }
            };
            new Thread(runnable).start();
        }
    } catch (IOException io) {
        MessageOutput.error("Server Connection Manager Failed...Shutting Down...", io);
        // if the connection manager fails we want to closedown the server
        System.exit(0);
    }
}

Then on the client side, I have something like this..

然后在客户端,我有这样的事情..

public void connect(String ip) {

        try {
            comms = new Socket(ip, 12345);
            comms.setTcpNoDelay(true);
             // get the streams from the socket and wrap them round a ZIP Stream
            // then wrap them around a reader and writer, as we are writing strings
             this.input =  new CompressedInputStream(comms.getInputStream());
             this.output = new CompressedOutputStream(comms.getOutputStream());
             this.connected = true;
             startServerResponseThread();

        } catch (IOException e) {
            ui.displayMessage("Unable to connect to server, please check and try again");
            this.connected = false;
        }

        if (connected) {
            String name = ui.getUserInput("Please choose a player name");
            sendXML(XMLUtil.getXML(new NameSetAction(name, Server.VERSION)));
        }
    }

    /**
    * This method sets up the server response thread. The thread, sits patiently
    * waiting for input from the server, in a seperate thread, so not to hold
    * up any client side activities. When data is recieved from the server
    * it is processed, to perform the appropriate action.
    */
   public void startServerResponseThread() {

      // create the runnable that will be used by the serverListenerThread,
      // to listen for requests from the server
      Runnable runnable = new Runnable() {

         public void run () {

            try {
               // loop forever, or until the server closes the connection
               while (true) {

                  processRequest(input.readCompressedString());
               }
            } catch (SocketException sx) {
               MessageOutput.error("Socket closed, user has shutdown the connection, or network has failed");
            } catch (IOException ex) {
               MessageOutput.error(ex.getMessage(), ex);
            } catch (Exception ex) {
               MessageOutput.error(ex.getMessage(), ex);
            } finally {
               (PRClone.this).connected = false;
               // only shutdown the server if the listener thread has not already been
               // destroyed, otherwise the server will have already been shutdown
               if (serverListenerThread != null) {
                  // shutdown the thread and inform the application the communications has closed
                  MessageOutput.debug("Shutting down server listener Thread");
               }
            }
         }
      };

      // create the thread
      serverListenerThread = new Thread(runnable);
      // start the thread
      serverListenerThread.start();

   }

The the client is able to send requests to the server via the outputstream, and read server data from the input stream.

客户端能够通过输出流向服务器发送请求,并从输入流中读取服务器数据。

The server can accept requests from the client, and process it in the GameController, and can also send notifications from the server using outputstream, again in the GameController.

服务器可以接受来自客户端的请求,并在 GameController 中处理它,也可以使用 outputstream 从服务器发送通知,再次在 GameController 中。

EDIT: Also, I should note that all my communication is done via XML, and the controller on the client or the server decodes the XML and performs the relevant request.

编辑:另外,我应该注意我所有的通信都是通过 XML 完成的,客户端或服务器上的控制器解码 XML 并执行相关请求。

Hope this helps. It certainly does the job for me, and allows my multi-player games to work well.

希望这可以帮助。它当然对我有用,并且让我的多人游戏运行良好。

回答by aioobe

I suspect that your client threads are hanging on a blocking read operation. To "release" these threads and make them senddata instead, you'd have to interrupt them through thread.interrupt(). (Which would cause the blocking read to throw an InterruptedException.)

我怀疑您的客户端线程挂在阻塞读取操作上。要“释放”这些线程并让它们发送数据,您必须通过 thread.interrupt() 来中断它们。(这会导致阻塞读取抛出 InterruptedException。)

However, I've written a few network games myself, and I would reallyrecommend you to look into the java.niopackagesand especially the Selectorclass. Using this class you could easily make the whole server single-threaded. This would save you a lotof headaches when it comes to synchronizing all those client threads.

但是,我自己写了一些网络游戏,我真的建议您查看java.nio,尤其Selectorclass。使用这个类,您可以轻松地使整个服务器成为单线程的。在同步所有这些客户端线程时,这将为您省去很多麻烦。

回答by Peter Tillemans

I think using an existing communication infrastructure like ActiveMQ would be very useful here to deal with the low-level piping stuff and allow you to tackle the game design issues at a higher conceptual level rather than dealing with the low-level intricacies.

我认为使用像 ActiveMQ 这样的现有通信基础设施在这里处理低级管道问题非常有用,并允许您在更高的概念级别上解决游戏设计问题,而不是处理低级的复杂性。

That being said. If I understood you then you have a game-client with mutiple threads, one of which deals with comms to the server. On the server there is a comms thread for each client and the game server logic.

话虽如此。如果我理解你,那么你有一个多线程的游戏客户端,其中一个处理与服务器的通信。在服务器上,每个客户端和游戏服务器逻辑都有一个通信线程。

I would only use sockets for remote communication and Queues for communication between the server threads. On the queues send immutable objects (or copies) back and forth so you do not need to synchronize access to the data in the messages. As a base for synchronisation you can block on the Socket or a BlockingQueue, then you do not need to manually synch things, however this requires careful protocol design.

我只会使用套接字进行远程通信,使用队列进行服务器线程之间的通信。在队列上来回发送不可变对象(或副本),因此您不需要同步对消息中数据的访问。作为同步的基础,您可以在 Socket 或 BlockingQueue 上阻塞,然后您不需要手动同步事物,但这需要仔细的协议设计。