2016-01-26 132 views
0

我寫這與服務器通信的TCP客戶端。在專門的「聆聽」線程中,我擁有如下代碼。只有在那裏有數據時才應該讀取數據。 (​​)偶爾讀讀C#TCP客戶端接收不到數據 - 「無」

奇怪的是,偶爾我,程序將會崩潰,因爲流將讀取絕對沒有數據。它將返回一個空的string。更奇怪的是,如果我嘗試在'handleResponse(string s)'函數中'捕捉'一個空字符串,它不會被捕獲。

public void listenForResponses() 
    { 
     Console.WriteLine ("Listening..."); 
     while (isConnected == true) 
     { 
      Thread.Sleep (updateRate); 
      String responseData = String.Empty; 

      if (stream.DataAvailable) { 
       Int32 bytes = stream.Read (data, 0, data.Length); 
       Console.WriteLine (" >> Data size = "+data.Length); 
       responseData = System.Text.Encoding.ASCII.GetString (data, 0, bytes); 
       output = responseData+""; 
       handleResponse (output); 
      } 
      if (isConnected == false) { 
       closeConnection(); 
      } 
     } 
    } 

public void handleResponse(string msg) 
{ 
    Console.WriteLine ("Received: "+msg); 
    iterateThroughEachCharInString (msg); 
    if ((msg != "")&&(msg != null)&&(msg != " ")) { 
     JSONDataObject desrlzdResp = JsonConvert.DeserializeObject<JSONDataObject>(msg); 

     if ((desrlzdResp.instruction != null)) { 
      if (desrlzdResp.instruction == "TestConn") { 
       handleTestConn (desrlzdResp); 
      } else if (desrlzdResp.instruction == "SceneOver") { 
       handleSceneFinished (desrlzdResp); 
      } 
     } 
    } 
} 

引發的異常是System.NullReferenceExceptionhandleResponse功能

+3

你假設一個發送()對應於一個接收(),但是這並不插槽如何工作。 'responseData'可以包含一個消息,多個或部分消息。您需要一個成幀協議來區分這些情況,例如,通過在數據前加上一個數字來指示後續有多少字節。嘗試seaching。 – CodeCaster

+1

好吧,看起來'desrlzdResp'爲空,因此在'JSONDataObject desrlzdResp = JsonDataverthe.DeserializeObject (msg)之後添加'if(desrlzdResp!= null)'''應該避免null參考異常 – Pikoh

+0

@Pikoh不,那麼你會失去數據。 'handleResponse()'可以接收部分或多個消息,導致'JsonConvert.DeserializeObject()'失敗。 OP需要確保他們只用完整的消息調用'handleResponse()'。 – CodeCaster

回答

3

網絡流有可用的廣告數據的習慣,即使他們不活躍的線if ((desrlzdResp.instruction != null))。此外,接收者無法知道傳入流是多長時間,除非發送者事先通告它。

 /// <summary> 
     /// Method designed to allow the sending of Byte[] data to the Peer 
     /// Because this is using NetworkStreams - the first 4 bytes sent is the data length 
     /// </summary> 
     /// <param name="TheMessage"></param> 
     public void SendBytesToPeer(byte[] TheMessage) 
     { 

      try 
      { 
       long len = TheMessage.Length; 

       byte[] Bytelen = BitConverter.GetBytes(len); 

       PeerStream.Write(Bytelen, 0, Bytelen.Length); 
       PeerStream.Flush(); 
       PeerStream.Write(TheMessage, 0, TheMessage.Length); 
       PeerStream.Flush(); 
      } 
      catch (Exception e) 
      { 
       //System.Windows.Forms.MessageBox.Show(e.ToString()); 
      } 
     } 

注 - 在發送端的沖洗可能並不需要,但我將其添加在,因爲它沒有壞處 - 微軟表示,沖洗無助於網絡流。

所以這個代碼將決定您要發送的郵件的大小,然後發送給你的未來「實際」消息的接收者。

 /// <summary> 
     /// Incoming bytes are retieved in this method 
     /// </summary> 
     /// <param name="disconnected"></param> 
     /// <returns></returns> 
     private byte[] ReceivedBytes(ref bool disconnected) 
     { 
      try 
      { 
       //byte[] myReadBuffer = new byte[1024]; 
       int receivedDataLength = 0; 
       byte[] data = { }; 
       int len = 0; 
       int i = 0; 
       PeerStream.ReadTimeout = 15000; 


       if (PeerStream.CanRead) 
       { 
        //networkStream.Read(byteLen, 0, 8) 
        byte[] byteLen = new byte[8]; 
        if (_client.Client.IsConnected() == false) 
        { 
         //Fire Disconnect event 
         if (OnDisconnect != null) 
         { 
          disconnected = true; 
          OnDisconnect(this); 
          return null; 
         } 
        } 
        while (len == 0) 
        { 
         PeerStream.Read(byteLen, 0, 8); 

         len = BitConverter.ToInt32(byteLen, 0); 
        } 
        data = new byte[len]; 

        PeerStream.Read(data, receivedDataLength, len); 

        return data; 
       } 



      } 
      catch (Exception E) 
      { 

       //System.Windows.Forms.MessageBox.Show("Exception:" + E.ToString()); 
      } 
      return null; 
     } 

此代碼將等待,直到接收方檢測到傳入流的長度,然後它會嘗試讀取確切的長度。 不要擔心OnDisconnect比特,這只是一些代碼,我從一個項目,我是做留英寸您可能需要考慮在while(len == 0)循環內添加Thread.Sleep,以節省您的CPU週期。

相關問題