Java套接字: Pushing requests to client through socket

标签 java sockets networking tcp client-server

我目前正在制作一个客户端-服务器应用程序,该应用程序主要是为了对服务器进行过程调用并等待数据包响应。

但是我想让服务器将消息“推送”给客户端(自发地),但是如果当客户端监听另一个数据包响应时消息到达,这似乎是一个问题。

有没有办法通过同一个套接字实例将套接字分成 2 个唯一的 channel 流?或者创建一个仅监听传入连接并将它们分派(dispatch)到队列的客户端线程会更好吗?

使用 2 路客户端-服务器连接时有哪些常见模式和实践? (溪流自发发生的地方)

提醒一下,我正在使用 Java Socket、ObjectInputStream 和 ObjectOutputstream。我没有使用 Java RMI。

最佳答案

因此,在学习网络时,您会遇到的问题之一就是失去同步。例如,当您“硬编码”一组特定的客户端-服务器交互时,就会发生这种情况;

server sends 2 byte status code
client receives 2 byte status code
client responds with 4 byte operation code

如果由于某种原因存在错误导致此交互的任何部分无法按照其需要精确发生,则程序的其余部分将失败,因为所有网络交互现在都不同步。客户端可能会读取一组它认为代表字符串的字节,而实际上服务器正在发送 int,等等。最糟糕的是,您可能会发现主网络线程死锁,因为客户端和服务器同时等待输入。

对于一个较大的项目,肯定存在错误,如果您以这种风格编写代码,这种情况将会发生很多。因此,我们有一个叫做中间件的东西。

一个非常常见且灵活的中间件范例是 TLV Message Protocol 。您将实现一些简单的类(用半 java 伪代码);

TLVMessage
    int type;
    byte[] value;

TLVPusher implements Runnable
    OutputStream out;
    Queue<TLVMessage> messages;
    run() {
        while(true) {
            //poll and write front of queue to out (INCLUDING value.length!)
        }
    }

TLVReader implements Runnable
    InputStream in;
    Queue<TLVMessage> messages;
    run() {
        while(true) {
            //read message from in and add to queue
        }
    }

现在您有两个线程在客户端上运行,两个线程在服务器上运行。每一端都有自己的 PusherReader。需要注意的重要一点是,因为您将 length 字段写入输出流,所以读取器总是知道它需要读取多少字节。因此,即使一条消息被错误地序列化,它的长度仍然是正确的,并且下一条消息将始终从第一个字节到最后一个字节被正确读取。这样您的程序就永远不会失去同步。

您只需将 TLVMessage 对象添加到 pusher.queue 中,它们就会到达队列另一端的 reader.queue socket 。然后,您可以通过消息的 type 字段处理消息(在另一个、第三个线程中,该线程监视 reader.messages.size())。

您无需担心事情发生的顺序,您有一个强大的机制可以在客户端和服务器之间以两个方向传递消息。您已经抽象出了繁琐的网络内容,可以继续编码。

当然有libraries为您完成所有这一切,但在我看来,了解如何为什么总是值得的。

关于Java套接字: Pushing requests to client through socket,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13266034/

相关文章:

java - 如何将多维json处理成3个数组

java - 如何将解决方案从递归方法调用传递到调用方法? (回溯算法)

Python 错误 : "socket.error: [Errno 11] Resource temporarily unavailable" when sending image

Java - DocumentBuilder 关闭 Socket 连接

networking - 如何查找标题数据和名称? (Python 请求)

java - 参数化枚举传入另一个枚举

java - 如何在Spring中使用Thymeleaf配置CharacterEncodingFilter?

java - Spring 集成和 TCP 服务器套接字 - 如何向客户端发送消息?

java - 就性能而言, `java.net` 和 `java.nio` 的替代方案是什么?

networking - 本地主机 :8080 mean? 是什么意思