簡體   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