2

我正在寻找编写一个基于客户端-服务器的小型文本游戏,它可以处理多个客户端连接并持续影响游戏状态。我想知道处理多个连接的最佳方法是什么,以便命令按照它们到达服务器的顺序进行处理。

理想情况下,我不希望利用多线程,至少在命令处理级别。我可以接受每个客户端都有一个单独的线程(以便在每个线程上都有阻塞 IO),只要我之后可以在单个线程中统一处理。

由于客户端和服务器之间的唯一通信将是文本,我不确定如何最好地设置通信。如果我选择阻塞 IO,我将如何让处理在单个线程中发生?

或者,如果我选择非阻塞 IO 并使用选择器来查询客户端何时写入服务器,如何在不使用设置大小的 ByteBuffer 的情况下读取未知/无限长度的字符串?非阻塞也有利于将处理保持在单个线程中,因为它可以在客户端连接发送新数据时读取它们。但是,当我尝试使用 read/writeUTF 来实现它时,我遇到了 IllegalBlockingModeException 呵呵。

对于如何以我未提及的方式执行此操作的问题或建议的任何答案将不胜感激!我对客户端和服务器还很陌生,所以我不知道 java.io 还是 java.nio 最合适。

抱歉这个令人费解的问题。我想我自己逃跑了。

4

2 回答 2

1

我不是服务器客户端系统方面的专家,但我将分享一些技巧

根据您的需要,您可以简单地设置一个 Tomcat 服务器并执行 http 请求,它相当简单,当然也都是 Java。

缺点是请求可能有点慢。

您可以签出的第二个选项是 RMI。

这个概念很简单,您连接到另一台计算机,完成后,您从代码中的本地对象调用另一台计算机上的方法。

http://java.sun.com/developer/onlineTraining/rmi/RMI.html

它可能看起来有点复杂(有时通过多台计算机调试堆栈有点棘手),但我建议这样做,因为它可以让你的代码保持清晰。

最后,您可以尝试使用套接字,但您可以自己尝试:P

于 2011-04-18T11:44:23.133 回答
1

意见不同,但我肯定会为每个客户端使用一个线程。然后,与单个处理线程的通信可以通过 LinkedBlockingQueue,或者只是一个同步的 LinkedList。

在每个客户端线程上是这样的:

public class Client implements Runnable, ResponseOutput {

    private final BufferedReader br;
    private final PrintWriter pw;

    public Client(Socket s) {
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        pw = new PrintWriter(s.getOutputStream());
    }

    // defined by the ResponseOutput interface
    public void sendReply(String reply) {
        pw.println(reply);
    }

    public void run() {
        try {
            while (true) {
                String s = br.readLine();
                if (s==null)
                    break;
                Processor.queue(new Processor.InputItem(this, s));
            }
        } catch (IOException ioe) {
            ... error handling ...
        }
    }
}

然后进行处理:

public class Processor implements Runnable {
    static public class InputItem {
        final ResponseOutput client;
        final String command;

        public InputItem(ResponseOutput client, String command) {
            this.client = client;
            this.command = command;
        }
    }

    static private Processor instance;
    static public void queue(InputItem item) {
        instance.commandQueue.add(item);
    }

    private BlockingQueue<InputItem> commandQueue;

    public void run() {
        try {
            while (true) {
                InputItem item = commandQueue.take();
                String reply = doStuff(item.command);
                item.client.sendReply(reply);
            }
        } catch (InterruptedException ie) {
            ... error handling ....
        }
    }
}

InputItem类中,您还可以包含对需要更新的任何游戏状态的引用。由于只有处理线程在更改它,因此您无需任何同步即可执行此操作。

于 2011-04-18T11:45:45.973 回答