2011-04-29 16 views
1

私はCサーバと通信するjava TCPクライアントを作成しています。 私は両者の間で送受信を交互にする必要があります。 ここに私のコードです。Java TCPクライアント送信がブロックされましたか?

  1. サーバはクライアントにバイナリMSG(LEN)の長さを送信する(Java)の
  2. クライアントが
  3. Serverは、バイナリを送信し、クライアントが「lenの」のバイト配列を割り当て、「OK」の文字列を送信しますそれを受け取るためのバイト。
  4. もう一度 "ok"を返します。

ステップ1.動作します。私は "len"値を取得します。しかし、クライアントは「送信ブロック」を取得し、サーバーはデータの受信を待機します。

誰でも見ることができます。

  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(); 
      } 

更新:ここで

が私のコードで私が定義したtryブロックで

。現時点では、どちらの側にもrecvやsendブロッキングはありません。ただし、Buffered ReaderとDataInput Streamリーダーの両方で、ok msgを送信できません。サーバー側では、okの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

答えて

3

ストリームの周りBufferedReaderを使用して、ストリームからバイナリデータを読み取ろうとすることは悪い考えです。サーバがの場合、実際にはがすべてのデータを一度に送信し、BufferedReaderが返された行と同様にバイナリデータを読み込んでも驚かないでしょう。

あなたはプロトコルを制御していますか?その場合は、データ長をバイナリ(固定4バイトなど)にして、テキストとバイナリを切り替える方法(基本的には痛み)を解消する必要がないように変更することをおすすめします。

これができない場合は、\nを表すバイトが表示されるまで一度に1バイトずつ読み込んでから、読み込んだ内容をテキストに変換して解析し、残りをチャンクとして読んでください。これは(一度にバッファを読み込むのではなく、一度にバイトを読み込む)やや非効率ですが、その時点で読み取られるデータの量はかなり少ないと思います。

+1

+1:代わりに、DataInputStreamをreadLine()とreadFully()で使用することもできます。 readLine()は理想的ではありませんが、ここでOPが望んでいることを行う可能性があります。 –

+0

@Peter:おそらく。それは理由のために非難されていますが、それは良い考えです。個人的には、プロトコルデザイナーがこのようにテキストとバイナリの混合をやめさせたいと思っています。 (もちろん、既知のサイズのバイナリブロック内にテキストをカプセル化しても問題ありません) –

+0

IMHO、あなたが何をしているのかについての非常に明確なアイデアがない限り、それらを混ぜ合わせるべきではありません。つまり、テキストとバイナリの要件を完全に理解し、必要に応じてプロトコルを文書化した後に限ります。 –

0

いくつかの考え:

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

あなたは、いくつかの理にかなっている最大に対して与えられたサイズを確認する必要があります。あなたのサーバーはクライアントに2ギガバイトのメッセージを送信することはほとんどありません。 (おそらくそれはありますが、より良い設計があるかもしれません:)通常、リモートクライアントの多くのメモリを割り当てることは望ましくありません。に割り当てを依頼します。それは簡単なリモート拒否攻撃に対するレシピです。

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

たぶんあなたBufferedReaderは、あまりにも多くのデータに吸い込まれたのか? (続行する前にサーバOkのためにを待っていますか?)BufferedReaderオブジェクトを添付した後に、基礎となるInputStreamReaderオブジェクトからの読み取りを許可してもよろしいですか?

TCPは、次の2週間で10バイトのチャンクでデータを配信できます:) - カプセル化やハードウェアの違いなどにより、最終的に使用されるパケットのサイズほとんどの特定の量のデータを探しているアプリケーションは、代わりにこのようなコードを使用してバッファを設定します(Unix環境での高度なプログラミング、優れた本、CでのコードとコードJavaにありますが、原則は同じです)。

バッファーを満たすには、1またはread()への100回の呼び出しであり、コードはネットワーク機能のわずかな変更に対して回復力がなければなりません。

+0

ありがとうsarnold。このバグを修正したら、バイト長を制限します。 – pimmling

関連する問題