管理基于文本的客户端 - 服务器连接的最佳方法是什么?

时间:2011-04-18 11:28:22

标签: java client mud

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

理想情况下,我不打算利用多线程,至少在命令处理级别上。我会很好,每个客户端都有一个单独的线程(为了在每个线程上都有阻塞IO),只要我可以在一个线程中统一处理。

由于客户端和服务器之间的唯一通信是文本,因此我不确定如何最好地设置通信。如果我选择阻止IO,我将如何在单个线程中对处理进行排队?

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

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

对于这个令人费解的问题感到抱歉。我想我和自己一起逃跑了。

2 个答案:

答案 0 :(得分:1)

我不是服务器客户端系统的专家,但我会分享一些提示

根据您的需要,您可以简单地设置一个Tomcat服务器并执行http请求,它是相当直接的前进,当然还有所有Java。

缺点是请求可能有点慢。

您可以查看的第二个选项是RMI。

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

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

它可能看起来有点复杂(有时候通过多台计算机重新堆叠堆栈有点棘手)但我建议因为它可以保持代码清晰。

最后你可以试试套接字,但你可以自己:P

答案 1 :(得分: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类中,您还可以包含对任何需要更新的游戏状态的引用。由于只有处理线程在改变它,所以你可以在没有任何同步的情况下做到这一点。