簡體   English   中英

通過TCP管理Java中的套接字連接

[英]manage socket connection in Java over tcp

我寫了一個客戶端,基本上只打開一個套接字並通過連接發送內容。 (內容遵循Http協議)

我所面臨的問題與該問題有關-我應如何以及何時關閉連接。 問題是連接有時關閉得太早(服務器應答之前,“ FIN”已發送到服務器)。

在這種情況下,服務器的答案將丟失。
我嘗試在關閉連接之前使用Thread.sleep,但似乎沒有任何影響到內容發送和“ FIN”消息發送之間的時間。 (在Wireshark中查看)

答案有時到來,有時卻沒有(比賽條件)。

我該如何延遲“ FIN”消息,以免錯過服務器的響應?

我添加了相關的課程。 相關功能是sendContentOverSocket

public class SocketClient {

           private String hostName;
           private int portNumber;
           private Socket ConnectionSocket;

           public void init(String hostName, int portNumber){
                          this.hostName = hostName;
                          this.portNumber = portNumber;
                          this.ConnectionSocket=createSocketConnection();

           }

           private Socket createSocketConnection() {
                          Socket socket = null;
                          try {
                                         socket = new Socket(this.hostName, this.portNumber);
                                         return socket;
                          } catch (UnknownHostException e) {
                                         e.printStackTrace();
                          } catch (IOException e) {
                                         e.printStackTrace();
                          }

                          return socket;
           }

           public void sendContentOverSocket(String content) {
                          try {
                                         PrintWriter out = new PrintWriter(
                                                                       ConnectionSocket.getOutputStream(), true);
                                         BufferedReader in = new BufferedReader(new InputStreamReader(
                                                                       ConnectionSocket.getInputStream()));
                                         out.print(content);

                                         try {
                                                        Thread.sleep(2000);
                                         } catch (InterruptedException e) {
                                                        // TODO Auto-generated catch block
                                                        e.printStackTrace();
                                         }

                                         out.close();
                                         in.close();                           
                                         ConnectionSocket.close();

                          } catch (IOException e) {
                                         e.printStackTrace();
                          }
           }

}

在此處輸入圖片說明

TCP使用稱為半封閉的概念。 當您關閉套接字時,這表示您將不再發送。 在您的解釋中,我看到“在服務器應答之前先將FIN發送到服務器”,如果您是客戶端,則意味着您已對套接字執行了關閉操作。 如果您希望服務器在特定時間內得到結果,則需要某種計時機制,可能將select與超時結合使用。 如果服務器關閉其連接的末端,則可以通過接收receive中的字節來檢測到這一點。 通常,這意味着您也必須關閉插座。 因此,總而言之,有3個原因可以關閉插座:

  • 服務器關閉了插座的一端,基本上是說我不再發送了
  • 您已經等待了一段時間,而又厭倦了等待並決定自己關閉插座。
  • 任何其他錯誤條件,但通常它們都看起來像接收0字節或負數。

當然,您應該在閱讀響應后關閉連接。 很難在這里看到這個謎。 沒睡 如果您不閱讀響應(a)您將無法知道請求是成功還是失敗,以及(b)服務器也有可能遇到異常。

您的代碼質量很差。 所有這些方法都應傳播異常,而不是在內部捕獲異常並返回null。

對於Java 7,由於所有三個類(即SocketPrintWriterBufferedReader )都實現AutoCloseable,並且基於這樣的事實,您想在調用sendContentOverSocket(String content)之后立即關閉套接字,請嘗試使用以下代碼:

    public class SocketClient {

    private String hostName;
    private int portNumber;

    public void init(String hostName, int portNumber) {
        this.hostName = hostName;
        this.portNumber = portNumber;
    }

    public void sendContentOverSocket(String content) {
        try (Socket socket = new Socket(this.hostName, this.portNumber);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
            out.print(content);
        } catch(IOException e) {
            //Appropriate exception handler
        }
    }
}

在這種情況下,Java將自行正確關閉所有資源。

如果您使用Java 6或更早版本,請嘗試使用try-finally塊代替:

解決了。

我現在了解它是如何工作的。 我在客戶端中缺少的是嘗試從輸入Stream讀取的內容。 當您嘗試閱讀時

while ((inputFromServer = in.readLine()) != null)

客戶端等待輸入。 唯一會打破此循環的是服務器關閉連接。

之后,您可以安全地在客戶端上關閉連接。 無需延遲FIN等

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM