2012-01-06 103 views
6

當我需要從服務器的藍牙套接字發送字符串到我的客戶端的藍牙套接字時,我遇到了麻煩。 一切正常,只要我一次只發送一個字符串(例如聊天),但如果我需要在短時間內寫入更多的字符串(以交換信息),則字符串不會與客戶端分離碼。例如,如果我發送「FirstUser」,並在此之後「SecondUser」,客戶端不會讀取「FirstUser」,然後讀取「SecondUser」。它會讀取「FirstUserSecondUser」。我怎樣才能避免這種行爲?藍牙連接;無法正確發送字符串

編輯:如果讓線程在能夠發送新消息之前先休眠,它會讀取正確的字符串,但此解決方案無法正常工作以滿足我的需要。

服務器的代碼:發送到所有客戶端(編輯)

public synchronized void sendToAll(String message) 
{ 
    try { 
     Thread.sleep(100); 
    } catch (InterruptedException e1) { 
     e1.printStackTrace(); 
    } 

    publishProgress(message); 
    for(OutputStream writer:outputList) { 
     try { 
      writer.write(message.getBytes()); 
      writer.flush(); 
     } catch (IOException e) { 
      System.out.println("Some-Error-Code"); 
     } 
    } 
} 

服務器的代碼:從客戶端閱讀:

public void run() { 
    String nachricht; 
    int numRead; 
    byte[] buffer = new byte[1024]; 
    while (runningFlag) 
    { 
     try { 
      if((numRead = inputStream.read(buffer)) >= 0) { 
       nachricht = new String(buffer, 0, numRead); 
       serverThread.handleMessage(nachricht); 
      } 
      } 
      catch (IOException e) { 
       this.cancel(); 
       e.printStackTrace(); 
      } 
    } 
} 

客戶代碼:從服務器讀取(編輯)

@Override 
    protected Void doInBackground(Integer... ints) {  
     String nachricht = new String(); 
     byte[] buffer = new byte[1024]; 
     int numRead; 
     while (runningFlag) 
     { 
      try { 
       if(((numRead = inputStream.read(buffer)) >= 0)) { 
        nachricht = new String(buffer, 0, numRead); 
        publishProgress(nachricht); 
       } 
      } 
      catch (IOException e) { 
       clientGame.finish(); 
       e.printStackTrace(); 
      }      
     } 
     return null; 
} 

客戶代碼:寫入服務器

public synchronized void write(String nachricht) 
    { 
     try { 
      Thread.sleep(100); 
     } catch (InterruptedException e1) { 
      e1.printStackTrace(); 
     } 

     try { 
      outputStream.write(nachricht.getBytes()); 
      outputStream.flush(); 
     } catch (IOException e) { 
      this.cancel(); 
      e.printStackTrace(); 
     } 
    } 

我感謝每一個小小的幫助:)。

+0

您的服務器是否向客戶端發送消息,反之亦然? – 2012-01-06 13:30:13

+0

兩種方式。在客戶端或服務器能夠發送另一個字符串之前,我暫時用Thread.sleep(100)「解決」了問題。但這不是一個很好的解決方案。 – Refrigerator 2012-01-06 16:28:46

+0

你是否沖洗所有發送的消息? – 2012-01-06 16:30:35

回答

8

您需要封裝您的數據項以避免串聯。 這意味着您必須在繼續之前編寫和讀取整個數據項。

你應該有一些實用的方法來做到這一點,而不是直接使用的OutputStream和InputStream的方法:

public static void writeItem(OutputStream out, String s) throws IOException 
{ 
    // Get the array of bytes for the string item: 
    byte[] bs = s.getBytes(); // as bytes 
    // Encapsulate by sending first the total length on 4 bytes : 
    // - bits 7..0 of length 
    out.write(bs.length);  // modulo 256 done by write method 
    // - bits 15..8 of length 
    out.write(bs.length>>>8); // modulo 256 done by write method 
    // - bits 23..16 of length 
    out.write(bs.length>>>16); // modulo 256 done by write method 
    // - bits 31..24 of length 
    out.write(bs.length>>>24); // modulo 256 done by write method 
    // Write the array content now: 
    out.write(bs); // Send the bytes 
    out.flush(); 
} 

public static String readItem(InputStream in) throws IOException 
{ 
    // first, read the total length on 4 bytes 
    // - if first byte is missing, end of stream reached 
    int len = in.read(); // 1 byte 
    if (len<0) throw new IOException("end of stream"); 
    // - the other 3 bytes of length are mandatory 
    for(int i=1;i<4;i++) // need 3 more bytes: 
    { 
     int n = in.read(); 
     if (n<0) throw new IOException("partial data"); 
     len |= n << (i<<3); // shift by 8,16,24 
    } 
    // Create the array to receive len bytes: 
    byte[] bs = new byte[len]; 
    // Read the len bytes into the created array 
    int ofs = 0; 
    while (len>0) // while there is some byte to read 
    { 
     int n = in.read(bs, ofs, len); // number of bytes actually read 
     if (n<0) throw new IOException("partial data"); 
     ofs += n; // update offset 
     len -= n; // update remaining number of bytes to read 
    } 
    // Transform bytes into String item: 
    return new String(bs); 
} 

然後你同時使用服務器&客戶端這些方法來讀取和寫入您的字符串項目。

+0

關於OutputStream.flush()的文檔說「這個實現什麼也不做」。這很正常,因爲OutputStream只是一個抽象類。實際的類(FileOutputStream,SocketOutputStream,...)會覆蓋此方法來執行某些操作。 – 2012-01-13 15:32:32

+0

我無法理解你的代碼。你可以試着解釋一下嗎?例如我從來沒有見過'>>>'和'| ='操作符。 爲什麼會有連接?爲什麼flush()不能解決問題? – Refrigerator 2012-01-13 17:28:28

+0

由於使用套接字,flush()不能保證您接收數據的時間,並且在OSI圖層和系統之間有多箇中間緩衝區。 – 2012-01-13 17:36:37