3

服务器本质上是一个项目队列,而客户端充当这些项目的生产者和/或消费者。

服务器必须:

  • 监听 put / take 请求并相应地处理它们 - 这通常不会花费太长时间,它包括:
    1. 解析短字符串;
    2. 一个HashMap.get;
    3. 获取锁;
    4. 一个PriorityQueue.pollPriorityQueue.offer;
  • 尽快通知每个客户所有项目活动,以便每个客户实时了解正在发生的事情。

设置它的最简单方法是拥有一个线程accept客户端,然后为每个客户端创建两个线程:

  • 一个处理InputStream,它阻塞等待请求;
  • 另一个处理OutputStream,它侦听队列中的事件,并将信息发送给客户端。

当然这是不可扩展的,并且为每个客户端设置两个线程似乎很浪费。

我还考虑过使用单线程,这将

  • 将套接字超时设置为read大约 1 秒;
  • read如果超时或处理请求后,继续将每个新事件发送给客户端;
  • 循环这两个动作。

但是,轮询请求和事件也是一种浪费。

另一种方法是使用线程池,并将上述两个动作中的每一个放在各自的Runnable. 然后,这些可运行文件将在Executor. 这似乎同样浪费,如果不是更多的话。

我一直在阅读一些 问题,现在我对 NIO 很好奇,因为非阻塞操作和事件驱动服务器似乎是正确的方法。

上述任何设计都适合这项任务,还是我应该用 NIO 来解决它?

就数字而言,这更像是一个练习,而不是一个真实的系统,因此它不必处理成千上万的客户,但理想情况下,它应该能够很好地执行和扩展。

4

4 回答 4

2

那么你需要继续使用 ThreadPool 因为你需要管理 Runners!,我建议你在你的业务中实现 MOA 结构,因为这个客户端连接到服务器并且服务器等待客户端请求(数据),然后服务器排队作业(如果没有可处理的线程)并立即响应一个指向服务器上客户端进程 ID 的长值并关闭套接字。现在如果客户的请求已经处理并准备好采取行动怎么办?所以这里有两种方法,好的一种是服务器向客户端发出信号(因此客户端需要监听服务器响应[ServerSocket])关于完成的请求。OR 客户端定期检查服务器并检查进程的状态。

于 2013-10-02T19:25:38.557 回答
1

我设计并实现了几个生产级实时系统(谈论毫秒级延迟或更少,但少数客户端)。恕我直言,您绝对应该采用 NIO 方法。

NIO 的核心基本上是 select() ,它允许您同时处理来自不同套接字/客户端的输入。之后,将事件放入适当的队列和/或在整个系统中广播。那么如何处理队列和分配线程完全独​​立于 IO 任务,取决于你自己的调优。

还可以看看 ZeroMQ,它基本上应用了相同的想法;看看他们的 Poller over multiple Socket 模型。我相信大多数现代消息传递框架,包括 JMS/EMS、TibcoRV、29 West LBM 等(现在属于 Informatica)都采用了类似的方法。

于 2013-10-03T03:26:57.323 回答
1

上面的设计完全没问题。这正是引入 nio 之前 Web 服务器的工作方式。

你有多少客户?如果不是很多,不要担心可扩展性,尽量避免复杂的 nio api。如果您真的需要扩展,请考虑使用某种抽象,例如 netty。使用 nio 可能相当复杂,并且在不同的操作系统上可能无法以相同的方式工作(一旦我遇到奇怪的错误,只能在特定的操作系统上重现)。

使用 nio,您可以在 1-4 个线程中处理所有客户端请求/响应流

有时 IO 可能会胜过 NIO。

请参阅此答案 -每个客户端模型或 NIO 反应器模式的旧 I/O 线程?

于 2013-10-02T19:59:50.430 回答
1

每个客户端两个线程绝对不可扩展。

如果服务器上有 M 个内核,实际上没有比运行 M 个线程更好的了。任何更高的值都会使您遭受颠簸,并会减少每秒执行的操作数。

更好的设计将可用内核划分为 U 个更新器和 L 个侦听器,其中 U + L == M。

每个客户端都被分配(理想情况下具有负载平衡,但这是一种修饰)到更新程序线程。每个更新事件都被多播到所有更新程序线程,然后每个更新程序更新所有分配给它们的客户端。更新者列表末尾的客户端比开头的更新晚,但没有任何帮助:您只有这么多硬件。

同样,每个客户端都分配给一个侦听器线程,该线程处理多个侦听器。客户端输入被转储到一个 FIFO 队列中,并在侦听器线程一到达它就被处理。

然后每个线程可以保持活动并在内存中,而客户端数据在系统中移动。设计优雅地降级,因为太多的客户端意味着所有更新都会变慢,这是客户端数量的线性函数。您提出的设计会比这更快地退化。

现代(例如,晚于 2002 年)的 Web 服务器将这一切都埋在了实现的深处,因此开发人员不需要管理它。但这仍然是一个有用的练习。

于 2013-10-02T19:10:20.880 回答