我在java中构建一个同时与多个客户端通信的服务器,我们的初始方法是服务器监听来自客户端的连接,一旦收到连接并创建套接字,新线程生成以处理与每个客户端的通信,即使用ObjectInputStream读取请求,执行所需操作(从数据库获取数据,更新数据等),并将响应发送回客户端(如果需要)。虽然服务器本身回去听更多的连接。
这暂时工作正常,但是这种方法并不是真正可扩展的,它适用于同时连接的少量客户端,但是由于每个客户端产生另一个线程,当有一个也会发生什么许多客户一次连接?
所以我的下一个想法是维护一个包含所有连接客户端(套接字对象和一些额外信息)的排序列表,使用ThreadPool迭代它们并读取它们发送的任何内容,如果收到消息则把它放在一个队列中,由另一个工作线程的ThreadPool执行,一旦工人完成了它的任务,如果需要响应,则发送它。
后两个步骤实现起来非常简单,问题是每个客户端实现的原始线程,我使用ObjectInputStream.readObject()来读取消息,这个方法阻塞,直到有东西要读,这是对于这种方法很好,但我不能对新方法使用相同的东西,因为如果我阻塞每个套接字,我将永远不会到达列表中的那些。
所以我需要一种方法来检查在调用readObject()之前是否有任何要阅读的内容,到目前为止我尝试了以下解决方案:
解决方案1: 使用ObjectInputStream.available()检查是否有可读的内容,此方法失败,因为此方法似乎总是返回0,无论流中是否有对象。所以这根本没有用。
解决方案2: 使用PushbackInputStream检查流中是否存在第一个未读字节,如果存在,则将其推回并使用ObjectInputStream读取对象,如果它不继续:
boolean available;
int b = pushbackinput.read();
if (b==-1)
available = false;
else
{
pushbackinput.unread(b);
available = true;
}
if (available)
{
Object message= objectinput.readObject();
// continue with what you need to do with that object
}
事实证明这也没用,因为如果没有要读取的输入,read()也会阻塞。如果流关闭,它似乎只返回-1选项。如果流仍然打开但是空它只是阻塞,所以这与简单地使用ObjectInputStream.readObject();
没有什么不同任何人都可以提出一种实际可行的方法吗?
答案 0 :(得分:1)
这是一个很好的问题,你已经完成了一些功课......但它涉及到历史记录以确保正确。注意,您的问题实际上更多地与套接字级通信而不是ObjectInputStream:
有关过去最简单的方法是每个插槽有一个单独的线程。这可以扩展到一定程度,但线程昂贵且创建缓慢。
作为回应,对于大型系统,人们创建线程池,并在有工作要做时为线程上的套接字提供服务。这很复杂。
然后使用java.nio包更改了Java语言,该包引入了Selector和非阻塞IO。这创建了一种可靠(尽管有时令人困惑)的方式来为多个线程服务多个套接字。在你的情况下,它不会完全/很多,因为你想知道什么时候准备好读取一个完整的对象,而不是只有'某些'对象。
在此期间,“格局”发生了变化,Java现在能够更有效地创建和管理线程。 “当前”的想法是,每个套接字再次分配单个线程更好/更快更容易....参见Java thread per connection model vs NIO
在你的情况下,我建议你坚持使用每插槽线程模型,你会没事的。
,Java可以扩展和处理比套接字更多的线程,所以你会没事的。