2017-03-05 72 views
1

我有一個android設備和一個服務器。服務器可以傳輸一條消息,告訴設備從wifi上斷開連接。要快速知道這是怎麼做的話,這裏有一個psudo序列圖:在緩衝讀取器中缺少第一個字符

Pseudo sd

現在,有趣的是,當客戶端重新連接,服務器發送一個消息,有時該消息丟失第一字符,有時它是下一個消息。無論如何,在客戶端重新連接之後它發生的很快。

而且例如環這裏示出,從服務器側看出:

 while (true) { 
     server_.transmitMessage("SLAVE", "WIFI"); 
     Thread.sleep(40000); 
     System.out.println("Should be back"); 
     server_.transmitMessage("SLAVE", "Hi wififims"); 
     Thread.sleep(5000); 
    } 

而從Android裝置的輸出:

03-05 15:36:01.200 17152-17180/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650 
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Received: WIFI 
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Client expecting disconnect. 
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Expecting disconnect. 
03-05 15:36:11.590 17152-17181/com.example.bla.psedowifidims I/System.out: Killing wifi 
03-05 15:36:16.660 17152-17181/com.example.bla.psedowifidims I/System.out: Enableing wifi 
03-05 15:36:31.760 17152-17181/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650 
03-05 15:36:51.550 17152-17181/com.example.bla.psedowifidims I/System.out: Received: Hi wififims 
03-05 15:36:56.780 17152-17181/com.example.bla.psedowifidims I/System.out: Received: IFI 

如最後一行所示,第二消息在重新連接有缺陷後發送。它應該是「無線網絡」。如果我讓了,而程序運行,比方說5分鐘,突然失蹤的人物帶有另一條消息:

03-05 15:52:32.480 17152-17181/com.example.bla.psedowifidims I/System.out: Received: WWWWWWWWWWWWIFI 

服務器

這裏顯示的監聽服務器:

public void startListening(int port) { 
    this.port = port; 
    canceled_ = false; 
    new Thread(() -> { 
     try { 
      System.out.println("Listening for incomming connections on port " + port); 
      serverSocket_ = new ServerSocket(port); 
      while (!canceled_) { 
       ServerClient serverClient = new ServerClient(serverSocket_.accept(), networkReceiver, server_); 
       serverClient.listen(); 
       serverClient.setIdWithoutTransmission(Long.toString(clientId++)); 
       this.ServerClientList_.add(serverClient); 
       networkReceiver.onNewClient(serverClient.getId()); 
       System.out.println("Client connected from:" + serverClient.getClientSocket().getInetAddress() + 
              serverClient.getClientSocket().getPort()); 
      } 

     } catch (IOException e) { 
      handleDisconnect(); 
     } 
    }).start(); 
} 

這組本地ServerClient處於監聽狀態:

public void listen() { 
    this.canceled_ = false; 
    new Thread(() -> { 
     while (!canceled_) { 
      try { 
       if (clientSocket_ == null) { 
        System.out.println("Socket is null, returning from listening"); 
        return; 
       } 
       clientSocket_.setSoTimeout(0); 
       BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket_ 
                           .getInputStream())); 
       String msg = inFromClient.readLine(); 
       if (msg == null) { 
        super.handleDisconnect(); 
        return; 
       } 
       if (handleMessage(msg)) 
        continue; 
       networkReceiver.onNewMessage(msg); 
      } catch (IOException e) { 
       super.handleDisconnect(); 
      } 
     } 
    }).start(); 

} 

當服務器發送到客戶端:

public void transmitMessage(String id, String msg) { 
    for (ServerClient ServerClient : ServerClientList_) { 
     System.out.println("Does " + id + " equals "+ ServerClient.getId()); 
     if (ServerClient.getId().equals(id)) { 
      ServerClient.transmitMessage(msg); 
      return; 
     } 
    } 
    System.out.println("Couldn't find ServerClient."); 
} 

並在serverclient的實際方法:

public void transmitMessage(String message) { 
    if (clientSocket_ == null || !clientSocket_.isBound()) { 
     System.out.println("Not connected, can't transmit. Make sure you are connected to the host\nClientsocket " + 
            "is null or not bound"); 
     return; 
    } 

    DataOutputStream outToServer = null; 
    try { 
     outToServer = new DataOutputStream(clientSocket_.getOutputStream()); 
     outToServer.writeBytes(message + '\n'); 
    } catch (IOException e) { 
     System.out.println("Error while writing to socket - message not delivered"); 

    } 

} 

處理服務器上的斷開(客戶端發送該處理的消息)。

private boolean handleMessage(final String msg) { 
    if (msg.equals(EXPECT_DISCONNECT_MSG)) { 
     EXPECT_DISCONNECT_FLAG(true); 
     return true; 
    } 

而當ServerClients監聽然後捕獲該異常,它然後看見升起的國旗,並呼籲:

protected void handleExpectedDisconnect() { 
    server_.lossOfClient(this); 
    this.canceled_ = true; 
    finalizeSockets(); 
} 

的lossOfClient很簡單:

public void lossOfClient(final ServerClient serverClient) { 
    this.ServerClientList_.remove(serverClient); 
    System.out.println("Removed client with ID " + serverClient.getId()); 
    System.out.println("Size: " + server_.getServerClientList().size()); 
} 

客戶

客戶端初始化機智^ h

public void connectAndListen(String host, int port) { 
    this.canceled_ = false; 
    try { 
     System.out.println("Conecting to " + host + ":" + port); 
     clientSocket_ = new Socket(host, port); 
     clientSocket_.setSoTimeout(2000); 
     listen(); 
    } catch (IOException e) { 
     System.out.println("Socket error - restarting"); 
    } 

} 

    public void listen() { 
    this.canceled_ = false; 
    new Thread(() -> { 
     while (!canceled_) { 
      try { 
       if (clientSocket_ == null) { 
        System.out.println("Socket is null, returning from listening"); 
        return; 
       } 
       clientSocket_.setSoTimeout(0); 
       BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket_ 
                           .getInputStream())); 
       String msg = inFromClient.readLine(); 
       if (msg == null) { 
        super.handleDisconnect(); 
        return; 
       } 
       if (handleMessage(msg)) 
        continue; 
       networkReceiver.onNewMessage(msg); 
      } catch (IOException e) { 
       super.handleDisconnect(); 
      } 
     } 
    }).start(); 

} 

和分離式:

public void disconnect() { 
    try { 
     if (clientSocket_ != null && clientSocket_.isBound()) { 
      System.out.println("Client expecting disconnect."); 
      EXPECT_DISCONNECT_FLAG(true); 
      transmitMessage(EXPECT_DISCONNECT_MSG); 
      Thread.sleep(500); 
     } 
     finalizeSockets(); 
    } catch (InterruptedException e) { 
     System.out.println("Coudln't inform receiver about expected disconnect."); 

    } 
} 

    public void finalizeSockets() { 
    if (clientSocket_ != null && clientSocket_.isBound()) { 
     try { 
      if (!clientSocket_.isClosed()) 
       clientSocket_.close(); 
     } catch (IOException e) { 
      System.out.println("Couldn't close clientsocket"); 
     } 
     clientSocket_ = null; 
    } 

} 

可有人告訴我,我在做什麼錯?爲什麼在斷開連接/重新連接之後收到的消息(雙方都是新套接字)無法傳輸整個消息?

編輯:

試圖刷新的OutputStream,以確保所有字節發送,儘管這並沒有幫助。 此致敬禮。

編輯II

嘗試:

DataOutputStream outToServer = null; 
BufferedReader inFromClient = null; 

,只有創建他們時,他們是空。當套接字關閉時,這些設置爲空。同樣的問題:

03-05 18:05:00.000 11383-11427/com.example.bla.psedowifidims I/System.out: 

Conecting to 192.168.1.77:6650 
03-05 18:05:06.470 11383-11428/com.example.bla.psedowifidims I/System.out: Received: Hi wififims 
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Received: WIFI 
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Client expecting disconnect. 
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Expecting disconnect. 
03-05 18:05:12.000 11383-11428/com.example.bla.psedowifidims I/System.out: Killing wifi 
03-05 18:05:17.090 11383-11428/com.example.bla.psedowifidims I/System.out: Enableing wifi 
03-05 18:05:32.180 11383-11428/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650 
03-05 18:05:51.530 11383-13368/com.example.bla.psedowifidims I/System.out: Received: i wififims 
03-05 18:05:56.560 11383-13368/com.example.bla.psedowifidims I/System.out: Received: IFI 
03-05 18:06:38.300 11383-11428/com.example.bla.psedowifidims I/System.out: Received: HWHi wififims 
03-05 18:06:43.340 11383-13368/com.example.bla.psedowifidims I/System.out: Received: WIFI 

編輯III 有了一絲Wireshark的我可以看到,有時像「WIFI」的消息被分裂成兩個包,W於一體,並在IFI其他。這看起來的原因,所以我嘗試:

public void listen(){ 
    .... 
      byte[] arbytes = new byte[inFromServer.readInt()]; 
      int length = arbytes.length; 
      inFromServer.read(arbytes,0,length); 
.... 
} 

和發射

public void transmitMessage(String message) { 

.... 
    try { 
     if(outToServer == null) 
      outToServer = new DataOutputStream(clientSocket_.getOutputStream()); 

     byte[] databyes = message.getBytes(Charset.forName("UTF-8")); 
     outToServer.writeInt(databyes.length); 
     outToServer.write(databyes); 

    } catch (IOException e) { 
     System.out.println("Error while writing to socket - message not delivered"); 

    } 

} 

雖然仍然沒有運氣:

03-05 20:01:10.810 27328-27353/com.example.bla.psedowifidims I/System.out: 

Conecting to 192.168.1.77:6650 
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Received: WIFI 
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Client expecting disconnect. 
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Expecting disconnect. 
03-05 20:01:22.110 27328-27354/com.example.bla.psedowifidims I/System.out: Killing wifi 
03-05 20:01:27.200 27328-27354/com.example.bla.psedowifidims I/System.out: Enableing wifi 
03-05 20:01:42.270 27328-27354/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650 
03-05 20:01:42.290 27328-27354/com.example.bla.psedowifidims I/System.out: Percent bad: 0.0 
03-05 20:02:01.560 27328-28467/com.example.bla.psedowifidims I/System.out: Received: ififims������� 
+0

嘿,你會改變這outToServer.writeBytes(消息+'\ n'); 在transmitMessage中向此outToServer.writeBytes((message +'\ n')。getBytes()); – Mehdi

+0

那麼,writeBytes接受一個字符串,不是嗎?因此,如果我使用getBytes,我必須使用它的String.ValueOf,然後它簡單地接收爲「Received:[B @ 682a0b20」:( –

+0

)將inFromServer更改爲DataInputStream並使用readFully並告訴我請 – Mehdi

回答

0

好了 - 我經歷了很多試驗去了。我嘗試手動發送要傳輸的數字字節,然後是數據,然後在客戶端做相應的處理。

雖然這個工作,當一個TCP重傳發生時,不知何故它得到了重傳包的大小錯誤。這對於WriteUTF等是一樣的。

不知何故 - 經過大量嘗試後,我將變送器改爲使用PrintWriter。

public void transmitMessage(String message) { 
    if (clientSocket_ == null || !clientSocket_.isBound()) { 
     System.out.println("Not connected, can't transmit. Make sure you are connected to the host\nClientsocket " + 
       "is null or not bound"); 
     return; 
    } 

    try { 
     if (outToServer == null) 
      outToServer = new DataOutputStream(clientSocket_.getOutputStream()); 


     PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket_.getOutputStream())), true); 
     pw.println(message); 
     pw.flush(); 

    } catch (IOException e) { 
     System.out.println("Error while writing to socket - message not delivered"); 

    } 

} 

現在一切正常 - 也在重傳過程中。 如果有人能告訴我爲什麼這個工程,我真的很感激它!