2014-09-28 37 views
-1

我已經很難調試這個問題兩天了。我在/ stackoverflow外搜索了很多內容後找不到答案。網絡響應緩衝區重寫壓力?

我正在爲定製的鍵/值服務器編寫客戶端。協議很簡單。 如果客戶端發送

"GET 1 12\r\nkey1\r\nkey2\r\n" 

服務器可以重放

"0 1 16\r\nvalue1\r\nvalue2\r\n" 

在響應中,第一行表示主體的長度是16個字節,併爲下一個16個字節,它包含了值兩個鍵。他們被「\ r \ n」分隔。

問題是,在壓力測試中,有時我從客戶端看到響應消息看起來不正確。它看起來像緩衝區被覆蓋。

例如發送

"GET 1 12\r\nkey1\r\nkey2\r\n" 

爲10,000次, 在響應緩衝區我可能會看到

"0 1 16\r\nvalue1\r\nval0 1 16" 

它看起來像值2這裏由一個響應部分覆蓋。

服務器在那裏工作了很長時間,我認爲它運行良好。我也使用tcpdump並證明它是正確的。所以錯誤應該在客戶端。

我遵循Netty Telnet示例here,並做了小的修改。

在DelimiterBasedFrameDecoder之後,一個處理程序逐個解析這些行並組裝響應。

我以爲它可能與多線程有關。但即使我把線程號設置爲1,問題重演。

那麼,我是否以錯誤的方式使用Netty?

====================

更新: 更多的調查之後,我發現它不與Netty的關係。即使使用簡單的java NIO程序,它也可以重新生成。它似乎與緩衝區溢出有關。

從tcpdump,我可以看到來自遠程服務器的包是正確的。

因此,我捕獲每個ByteBuffer,並在發生錯誤時將其打印出來。

protected void onRead(ByteBuffer buf) throws Exception { 
     buf.mark(); 
     int l = buf.limit(); 
     int p = buf.position(); 
     byte[] bytes = new byte[l - p]; 
     buf.get(bytes, p, l - p); 
     String v = new String(bytes, Charset.forName("UTF-8")); 
     buffers.addFirst(v); 
     if (buffers.size() > 30) { 
      buffers.removeLast(); 
     } 
     buf.reset(); 
     //... 
     // process one line of buf 

}; 

以下是最後三個緩衝器捕獲,因爲我處理它逐行:與此代碼 - (1K我故意將緩衝區大小設置爲小的數目。)。看起來頭部「0 0 1040」錯誤放置了一個截斷線「20」

************************************* 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
0 0 1040^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
200 0 1040^M 
20131101/booking.com.png^M 

************************************* 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
0 0 1040^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20 
************************************* 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
0 0 1040^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/booking.com.png^M 
20131101/boo 
************************************* 

我沒有找到根本原因。一旦我得到答案,我會回覆它。

=====================

這是我原來的代碼片段, 初始化

@Override 
    public void initChannel(SocketChannel ch) { 
     ChannelPipeline pipeline = ch.pipeline(); 

     pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 
     pipeline.addLast(DECODER); 
     pipeline.addLast(ENCODER); 

     pipeline.addLast(new NettyClientHandler()); 
    } 

和處理程序:

//@Sharable 
public class NettyClientHandler extends SimpleChannelInboundHandler<String> { 
    boolean head = true; 
    int len = -1; 
    ArrayList<String> vals = new ArrayList<>(); 

    @Override 
    public void channelRead0(ChannelHandlerContext ctx, String request) throws InterruptedException { 
     if (head) { 
      vals.clear(); 
      String[] splits = request.split(" "); 
      len = -1; 
      try { 
       len = Integer.parseInt(splits[2]); 
      } catch (NumberFormatException ex) { 
       ex.printStackTrace(); 
      } 
      if (len == -1) { 
       return; 
      } 
      head = false; 
     } else { 
      vals.add(request); 
      len -= (request.length() + 2); 
      if (len == 0) { 
//    System.err.print("["); 
//    for (int i = 0; i < vals.size(); i++) { 
//     System.err.print(vals.get(i) + ","); 
//    } 
//    System.err.println("]"); 
       head = true; 
      } 
     } 
     //System.err.println(request); 
    } 

    @Override 
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 
     cause.printStackTrace(); 
     ctx.close(); 
    } 
} 

回答

-1

經過調查,結果有點令人失望。服務器有一個錯誤。

回想起來,我在這裏學到了一些東西。

  • TCP不能錯。我正在考慮緩衝區溢出或其他什麼, 但TCP擁塞控制,所以這不會發生;
  • 我可以使用一個簡單的程序來測試服務器,例如一個簡單的 雙線程舊IO程序。
  • NCAT是爲了驗證這個easist辦法,那就是,準備大 包,並使用NCAT獲得響應〜
0

你假設有這樣的事情在TCP的消息。沒有。這是一個字節流。它可以完全根據它的奇想提供零個,一個或多個字節。如果您希望獲得特定的消息長度,則取決於您是否要循環,直到獲得它,如果更少,或者將您已收到的內容分開,如果更多。