仅当套接字的输入流包含数据时,服务器才会从该流字中读取数据

Server reading from the socket's input stream only if it has data

提问人:JoreJoh 提问时间:9/13/2023 更新时间:9/13/2023 访问量:33

问:

我正在尝试实现一个简单得离谱的聊天客户端和聊天服务器。我的目标是学会适应 s,而不是想出一个合理的聊天实现。但是,我想确保常识也得到尊重。这个问题是关于服务器代码的Socket

假设,一个连接已经建立(返回),现在服务器需要为该特定客户端提供服务(应该使用单独的线程)accept()

public class SimpleChatServer {
    // possibly something else
    private static final ExecutorService executorService = Executors.newCachedThreadPool();
    private static final List<OutputStream> outputStreamList = new ArrayList<>();

    public static void main(String[] args) {
        start();
    }

    @SneakyThrows
    private static void start() {
        try (var serverSocket = new ServerSocket(5000)) {
            while (true) {
                Socket socket = serverSocket.accept();
                executorService.submit(() -> serviceClient(socket));
            }
        }
    }

现在,我需要一个合理的实施。第一步是注册该套接字的输出流,因为服务器需要读取传入的字符串并将它们“广播”到每个连接的客户端serviceClient()

    private static void serviceClient(Socket socket) {
        registerOutputStream(socket);
        // some other code I haven't written yet
    }
    private static void registerOutputStream(Socket socket) throws IOException {
        // so that I "foreach" it once I receive a message to broadcast
        outputStreamList.add(socket.getOutputStream());
    }

现在我不知所措。该服务器如何知道客户端是否编写了某些内容,以便它可以从套接字的输入流中读取?我需要的代码基本上是这样说的,“如果输入流有东西,读取并广播给客户端;如果没有,就继续等待,直到它发生”。听起来很像一个无限循环,具有恒定的条件检查(效率低下)。或者客户端需要能够与服务器通信,“我写了,你可以读”。它可以使用并发同步机制来实现,但让客户端和服务器具有共享同步对象(即使对于如此简单的应用程序)也是一个奇怪的设计功能。对此的合理解决方案是什么?

我不认为“你有没有看过异步 IO”可能是一个充分的答案。如果这确实是我应该考虑的,你能提供一些细节(可能是简单的代码片段)吗?我对那个包不是很熟悉

Java 套接字 IO

评论

2赞 President James K. Polk 9/13/2023
您是否考虑过为每个客户端设置两个线程,一个用于从套接字读取,另一个用于写入套接字?读取器线程通常在读取时阻塞。
0赞 JoreJoh 9/13/2023
@PresidentJamesK.Polk 我有,但我仍然需要弄清楚如何避免一直检查条件并引入客户端和服务器共享的同步器。什么时候该读书了?
0赞 Remy Lebeau 9/13/2023
默认情况下,套接字在阻塞模式下运行。因此,您可以简单地无条件地读取它,并让它阻塞调用线程,直到数据到达。如果不想阻止调用线程,则必须使用非阻塞/异步 I/O(例如通过 )在数据可供读取时通知您。Selector
0赞 user207421 9/13/2023
“该服务器如何知道客户端是否编写了某些内容,以便它可以从套接字的输入流中读取?”:通过从输入流读取。毫无疑问,有人会建议,但这并不能保证完整的消息是可用的,除非你神奇地提前知道长度,所以这不是一个可行的解决方案。InputStream.available()

答: 暂无答案