作为练习,我们将实现一个服务器,该服务器具有一个监听连接、接受连接并将套接字放入 BlockingQueue 的线程。然后,池中的一组工作线程遍历队列并处理通过套接字传入的请求。
每个客户端连接到服务器,发送大量请求(在发送下一个请求之前等待响应)并最终在完成后断开连接。
我当前的方法是让每个工作线程在队列上等待,获取套接字,然后处理一个请求,最后将(仍然打开的)套接字放回到队列中,然后再处理另一个可能来自不同客户端的请求。客户端的数量比工作线程的数量多得多,因此有很多连接排队。
这种方法的问题是:即使客户端没有发送任何内容,线程也会被客户端阻塞。可能的伪解决方案,均不令人满意:
- 在
inputStream
上调用available()
,如果返回0,则将连接放回队列。问题:无法检测客户端是否仍然连接. - 如上所述,但使用
socket.isClosed()
或socket.isConnected()
来确定客户端是否仍处于连接状态。问题:这两种方法都没有检测到客户端挂起,正如 EJP 在 Java socket API: How to tell if a connection has been closed? 中很好地描述的那样。 - 通过读取或写入客户端来探测客户端是否仍然存在。问题:读取 block (即回到不活动客户端阻塞队列的原始情况)和写入实际上向客户端发送一些内容,导致测试失败。
有办法解决这个问题吗? IE。是否可以在不阻止或发送某些内容的情况下区分断开连接的客户端和被动客户端?
最佳答案
简短回答:不。如需更长的答案,请参阅 EJP 的答案。
这就是为什么您可能根本不应该将套接字放回队列,而是处理来自套接字的所有请求,然后将其关闭。将连接传递给不同的工作线程来分别处理请求不会给您带来任何优势。
如果您的客户端表现不佳,您可以在套接字上使用读取超时,因此读取只会阻塞,直到超时发生。然后您可以关闭该套接字,因为您的服务器没有时间迎合表现不佳的客户端。
关于Java:使用队列管理比线程更多的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46666269/