繁体   English   中英

Java 套接字阻塞

[英]Java socket blocking

我正在尝试使用多个客户端连接创建服务器。 客户端首先发送用户输入的命令。然后服务器读取所有参数并将其作为对象发送给服务器。

但我的问题是,在一个命令之后,我的程序陷入僵局。 我做了一个解决方法,所以我的客户端发送命令,然后在服务器之后 - 说你可以发送查询 - 对象。 我怎样才能避免这种解决方法?

这是我的服务器。

try {
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            objectOut = new ObjectOutputStream(clientSocket.getOutputStream());
            objectIn = new ObjectInputStream(clientSocket.getInputStream());
            // communicate with client
            if ("Hello Server".equals(in.readLine())) {
                out.println("Connection with Server established");
            }
            else {
                out.println("You picked the wrong house, fool! (wrong greeting)");
            }
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                if ("exit".equals(inputLine)) {
                    break;
                }
                else if ("ls".equals(inputLine)) {
                    execute_ls();
                }
                else if ("data".equals(inputLine)) {
                    out.println("o");
                    var query = (Query) objectIn.readObject();
                    exceute_data(query);
                }
            }

            in.close();
            out.close();
            clientSocket.close();
        } catch (Exception e) {
            Logger.err(e.toString());
        }

这是我在客户端的功能。

 public CompletableFuture<Data> queryData(param) {
        Data data_from_server;
        CompletableFuture<Data> data_series = new CompletableFuture<>();
        try {
            outputData.println("data");
            inputData.readLine();
            objectOutputData.writeObject(param);

            data_from_server = (Data) objectInputData.readObject();
            data_series.complete(data_from_server);

            if (data_from_server.getErrorMessage() != null) {
                throw new Exception(data_from_server.getErrorMessage());
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return data_series;
    }

在此先感谢各位!

您认为BufferedReader “缓冲”代表什么?

作为一项规则,您不能围绕同一个“源”输入流或读取器对象创建多个包装器,并期望一切正常工作 - 过滤器流(那些不是源的流,但您环绕另一个流;BufferedReader 是这种事情的一个例子,就像 InputStreamReader)被允许从底层输入源读取比提供任何请求数据所严格要求的更多; 某些过滤器流,例如 BufferedReader,实际上是明确指定的(例如,这是 BR 所做的唯一事情,因此得名)。

解决方案是永远不要有混合流。 要“取消混合”此流,请定义一个协议。 例如:

首先,客户端发送 1 个字节,表示它即将发送的命令的长度。 然后,它发送那么多字节(注意: BYTES ,而不是字符,你不应该在这里创建任何类型的 Reader 对象),然后你使用 US_ASCII 编码将其转换为一个字符串,然后对于每个命令你跳转到一个单独的代码片段。 例如,'exit' 命令不需要发送更多数据,但 'data' 命令将发送一个大端 32 位值,其中包含以下数据的大小。 然后使用 java 的内置序列化机制(即 ObjectInputStream)读取和解释该数据。

等等。

这导致了更多的认识:Java 内置的序列化机制几乎完全不适合这项工作; 这是一个你无法描述的协议(除了:“获取这个类文件,找到一个 JVM,确保类文件在它的类路径上,创建一个 ObjectInputStream,并在它上面调用 readObject”),这是非常低效的,充斥着如果您只坚持使用 java(在面对序列化对象时更改代码非常棘手),并且如果您向链中添加任何不是用 java 编写的工具,则无法阅读。 我建议你用别的东西。

一些替代方案:

  • 使用例如GSONJackson 将对象序列化为 JSON。
  • ProtoBuf用于整个协议(不仅是数据本身,还有您发送的那些命令)。
  • 做一个REST接口; 而不是发送命令和二进制数据混合的长期 TCP/IP 连接,而是让客户端调用例如https://yourserver.com/api/listAll ,在标头中使用某种身份验证令牌和/或会话令牌,如果在命令调用之间有要记住的状态数据。 然后在网络上搜索如何在 Java 中创建 REST API,您会发现大量选项,例如 JAX-RS 实现,如JerseySpark
  • 从相同的底层数据中摒弃多个过滤流的想法,而是使用原始InputStream ,仔细阅读您需要的内容,并在几乎所有内容前加上“大小”以了解要读取的内容,而不会意外读取很多。 这相当复杂,这就是为什么我建议您不要采用此计划,而是选择上述其他 3 个选项之一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM