2011-04-29 121 views
1

我正在寫一個與C服務器交談的java TCP客戶端。 我必須在兩者之間交替發送和接收。 這是我的代碼。Java TCP客戶端發送被阻止?

  1. 服務器發送二進制MSG(LEN)的長度至客戶端(JAVA)
  2. 客戶端發送一個「OK」的字符串
  3. 服務器發送二進制和客戶端分配的「len個」的字節數組字節來接收它。
  4. 它再次發回「ok」。

第1步工作。我獲得「len」的價值。然而,客戶端「發送阻止」,服務器等待接收數據。

有人可以看看。

在try塊我已經定義:

  Socket echoSocket = new Socket("192.168.178.20",2400); 
      OutputStream os = echoSocket.getOutputStream();  
      InputStream ins = echoSocket.getInputStream(); 
      BufferedReader br = new BufferedReader(new InputStreamReader(ins)); 

      String fromPU = null; 


      if((fromPU = br.readLine()) != null){ 
      System.out.println("Pu returns as="+fromPU); 

      len = Integer.parseInt(fromPU.trim()); 
      System.out.println("value of len from PU="+len); 

      byte[] str = "Ok\n".getBytes(); 
      os.write(str, 0, str.length); 
      os.flush(); 

      byte[] buffer = new byte[len]; 
      int bytes; 
      StringBuilder curMsg = new StringBuilder(); 
      bytes =ins.read(buffer); 
      System.out.println("bytes="+bytes); 
      curMsg.append(new String(buffer, 0, bytes));    
      System.out.println("ciphertext="+curMsg); 
        os.write(str, 0, str.length); 
      os.flush(); 
      } 

更新:

這裏是我的代碼。目前,雙方都沒有收到或發送封鎖。但是,無論是使用Buffered Reader還是DataInput Stream閱讀器,我都無法發送ok msg。在服務器端,我得到大量的字節而不是2個字節。

  Socket echoSocket = new Socket("192.168.178.20",2400); 
      OutputStream os = echoSocket.getOutputStream(); 
      InputStream ins = echoSocket.getInputStream(); 
      BufferedReader br = new BufferedReader(new InputStreamReader(ins)); 
      DataInputStream dis = new DataInputStream(ins); 
      DataOutputStream dos = new DataOutputStream(os); 
      if((fromPU = dis.readLine()) != null){ 
      //if((fromPU = br.readLine()) != null){ 
      System.out.println("PU Server returns length as="+fromPU);  
      len = Integer.parseInt(fromPU.trim()); 
      byte[] str = "Ok".getBytes(); 
      System.out.println("str.length="+str.length); 
      dos.writeInt(str.length); 
      if (str.length > 0) { 
        dos.write(str, 0, str.length); 
       System.out.println("sent ok"); 
      } 
      byte[] buffer = new byte[len]; 
      int bytes; 
      StringBuilder curMsg = new StringBuilder(); 
      bytes =ins.read(buffer); 
      System.out.println("bytes="+bytes); 
       curMsg.append(new String(buffer, 0, bytes));    
       System.out.println("binarytext="+curMsg); 

      dos.writeInt(str.length); 
      if (str.length > 0) { 
        dos.write(str, 0, str.length); 
       System.out.println("sent ok"); 
      } 
+0

你是什麼意思'客戶端發送阻止'?你嘗試調試嗎? – hage 2011-04-29 08:47:43

回答

3

在流的周圍使用BufferedReader,然後嘗試從流中讀取二進制數據是個壞主意。如果服務器有實際上一次發送所有數據,並且BufferedReader已經讀取二進制數據以及它返回的行,我不會感到驚訝。

你在控制協議嗎?如果是這樣,我建議你改變它發送的數據長度爲二進制(例如一個固定的4字節),這樣你就不需要了解如何在文本和二進制之間切換(這基本上是一個痛苦)。

如果你不能這樣做,你可能需要一次只讀一個字節,直到你看到代表\n的字節,然後將你讀的內容轉換成文本,解析它,然後然後將其餘的作爲一個塊讀取。這有點低效(一次讀取一個字節,而不是一次讀取一個緩衝區),但我想象的是,在這一點上讀取的數據量非常小。

+1

+1:另一種方法是使用帶有readLine()和readFully()的DataInputStream。雖然readLine()並不理想,但它可能會做OP在這裏所要的。 – 2011-04-29 08:52:41

+0

@彼得:可能。它由於某種原因而被棄用,但這是一個很好的想法。就我個人而言,我希望協議設計人員以這種方式停止混合文本和二進制。 (當然,將文本封裝在已知大小的二進制塊中是很好的,這是不同的。) – 2011-04-29 08:55:01

+0

恕我直言,你當然不應該混淆它們,除非你對你在做什麼有非常清楚的概念。即只有在您充分理解了文本和二進制文件的要求後,才能根據需要記錄協議。 – 2011-04-29 09:01:35

0

的幾點思考:

 len = Integer.parseInt(fromPU.trim()); 

你應該與最大的是有一定道理檢查給定大小。您的服務器不太可能向客戶端發送兩千兆字節的消息。 (也許它會,但可能會有更好的設計:)你通常不想分配一個遠程客戶端的內存,但要求你分配。這是容易發生遠程拒絕服務攻擊的祕訣。

 BufferedReader br = new BufferedReader(new InputStreamReader(ins)); 
     /* ... */ 
     bytes =ins.read(buffer); 

也許BufferedReader已經在太多的數據吸? (在繼續之前,服務器是否等待Ok?)您確定允許您在附加BufferedReader對象後從底層InputStreamReader對象中讀取數據嗎?

請注意,TCP可以在接下來的兩週內以十個字節塊自由發送數據:) - 因爲封裝,不同的硬件等等,很難分辨最終將使用的數據包的大小在兩個同行之間,大多數正在尋找特定數據量的應用程序將使用類似於此的代碼填充其緩衝區(從Unix環境中的高級編程中偷取了一本優秀的書;可惜代碼是用C語言編寫的,並且代碼在Java中,但原理是一樣的):

ssize_t    /* Read "n" bytes from a descriptor */ 
readn(int fd, void *ptr, size_t n) 
{ 
    size_t  nleft; 
    ssize_t  nread; 

    nleft = n; 
    while (nleft > 0) { 
     if ((nread = read(fd, ptr, nleft)) < 0) { 
      if (nleft == n) 
       return(-1); /* error, return -1 */ 
      else 
       break;  /* error, return amount read so far */ 
     } else if (nread == 0) { 
      break;   /* EOF */ 
     } 
     nleft -= nread; 
     ptr += nread; 
    } 
    return(n - nleft);  /* return >= 0 */ 
} 

帶走的是,填補你的緩衝區可能拿一個,點t en,或撥打read()的一百個電話,並且您的代碼必須能夠適應網絡功能的輕微變化。

+0

謝謝sarnold。一旦我修復了這個bug,我將限制字節長度。 – pimmling 2011-04-29 13:57:49