2012-04-16 8 views
8

、messageRevieved方法は、私はのNettyでは、1024バイト未満のデータしか書き込めず、受け取ることができます。ハンドラ上で2048bytesを書くとき

コードで2048bytesデータを受信することができる方法を...すべてのデータを受信するために二回呼び出されるべき

サーバー:

public class Server{ 
    public static void main(String[] args){ 
     ChannelFactory factory=new NioServerSocketChannelFactory(
      Executors.newCachedThreadPool(), 
      Executors.newCachedThreadPool()); 
     ServerBootstrap bootstrap=new ServerBootstrap(factory); 
     bootstrap.setPipelineFactory(new CarPipelineFactory()); 

     bootstrap.setOption("child.tcpNoDelay", true); 
     bootstrap.setOption("child.keepAlive", true); 

     bootstrap.bind(new InetSocketAddress(8989)); 
    } 
} 

サーバ・ハンドラ:

public class ServerHandler extends SimpleChannelHandler{ 

    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){ 
     byte[] resp=data.getBytes();//data is a String greater than 1024bytes; 
     ChannelBuffer buffer=ChannelBuffers.buffer(resp.length); 
     buffer.writerBytes(resp); 
     e.getChannel().write(buffer); 
     buffer.clear(); 
    } 
} 

クライアント:

public class Client{ 
    public static void main(String[] args){ 
     ChannelFactory channelFactory=new NioClientSocketChannelFactory(
      Executors.newCachedThreadPool(), 
      Executors.newCachedThreadPool()); 
     ClientBootstrap bootstrap=new ClientBootstrap(channelFactory); 
     bootstrap.getPipeline().addLast("handler", new PhoneClientHandler()); 

     bootstrap.setOption("child.tcpNoDelay", true); 
     bootstrap.setOption("child.keepAlive", true); 

     bootstrap.connect(new InetSocketAddress("127.0.0.1",8181)); 
    } 
} 

クライアントハンドラ:

public class ClientHandler extends SimpleChannelHandler{ 
    public void messageRecieved(ChannelHandlerContext ctx, ChannelStateEvent e){ 
     ChannelBuffer buffer=(ChannelBuffer)e.getMessage(); 
     int size=buffer.readableBytes(); 
     byte[] bytes=new byte[size]; 
     buffer.readBytes(bytes); 
     buffer.clear(); 
     System.out.println(new String(bytes));//if the data size>1024,the String will speprate into parts. 
    } 
} 
+0

は申し訳ありません。あなたはもっと具体的にしようとすることができますか? –

+0

すみません、私は中国語です。私の英語は良くありません。私はnettyを使用しているので、2048バイト(1024バイト以上)のデータを片方の手から別の手に書き込むと、手を2回受け取る必要があります。データ(1024バイト以上)を一度に? – Gofier

答えて

5

さてあなたは、常に時間に書き込むためにどのように多くのバイト数を決めることができますが、いつ、どのように多くのあなたは間違いなく知っていることはありませんバイトが受信されます(NIOが理にかなっている理由です)。必要な修正バイト数を受け取るために、独自のバッファーを処理する必要があります。これを行うには、この目的のために設計されたFrameDecoderを使用することができます。

Additionaly、あなたは件のデータがtrueにTCPNODELAYを設定することにより、送信元のソケットバッファに長すぎる滞在していませんことを確認することができますので、現在の「フレーム」のための待機は物理的に送信する前に一定の臨界サイズに達するないようにしますデータ。

私がよく理解すれば、片方の手で2048バイトと書いていますが、一方ですべてのデータがmessagedReceivedイベントで受信されていませんか?これらの一般的な問題をチェックしてみ :

  • あなたのアプリケーションは時期尚早終了し、件のデータがまだあなたが近いなかったので
  • あなた件のデータが「送信者」のソケットバッファにstuckedている到着していませんチャネルとtcpNoDelayオプションがtrueに設定されていませんでした。これは、パケットを送信する前にソケットがいくつかの追加のバイトを待つ原因となります。
  • あなたは私達にあなたのコードの一部を表示するようにしてくださいさらに位置

に設定されてChannelBuffer内部が、readerIndex理由で、すべての件のデータを読んでいない、それは物事を簡単にする必要があります。 ..

ADDED 17/04/2012

私はあなたが送信機から受信機への文字列をコードするバイト配列を渡すためにしようとしている理解していれば。 littelリファクタリング後のコードは次のとおりです。

----------------------------コード-------- --------------------手書き:応答。サイズ()> 1024バイト

byte[] datas = ((String)msg).getBytes("UTF-8"); //ALWAYS SPECIFY THE ENCODING 
ChannelBuffer buffer = ChannelBuffers.wrap(datas); //USE DIRECTLY THE ARRAY 
System.out.println(buffer); //buffer'size>1024 here 
channel.write(buffer); 

-----------------------------手を受け取る:println()を2回受け取る必要があります。二回

ChannelBuffer buffer = (ChannelBuffer) event.getMessage(); 
System.out.println(buffer) //buffer'size once 1024,once the remainder size 
byte[] datas =buffer.readBytes(buffer.readableBytes()).array() 
String msg=new String(datas , "UTF-8"); //BAD IDEA because the bytes sequence of the last UTF-8 char could be uncompleted there 
System.out.println(str); 

これは、あなたの代わりにをorg.jboss.netty.handler.codec.stringパッケージに直接StringEncoderStringDecoderを使用する必要があることを行うための方法ではありません実行します。それはあなたのためのフレーミングの問題を処理します。 コードをデバッグする場合は、Nettyが提供するLoggingHandlerを使用してください。両サイドのブートストラップで

bootstrap.setOption("tcpNoDelay", true); 

: はまた、あなたは本当にこのオプションを設定したのですか?

+0

まず、私の質問に答えてくれてありがとう、私はとてもうまくいきません。あなたが言ったように、私がハンドラで2048bytesを書くとき、messageRevievedメソッドは2回呼び出してすべてのデータを受け取るべきです...私は今、私のコードを表示します、あなたはagianに感謝します。 – Gofier

+0

本当にありがとうございます! NumRenaud、私はあなたが提案したように私のコードを変更しましたが、問題はまだ残っています。私はオプションbootstrap.setOption( "tcpNoDelay"、true)を両方の側で設定していることを確信しています。また、 "child.tcpNoDelay"両方とも "SimpleChannelHandler"。 – Gofier

+0

クライアントのbootstrap.setOption( "tcpNoDelay"、true)と サーバのbootstrap.setOption( "child.tcpNoDelay"、true) – RenaudBlue

2

まず第一に、クライアントのために、ブートストラップのオプションは、「子」で始めるべきではありません。

bootstrap.setOption("tcpNoDelay", true); 
bootstrap.setOption("keepAlive", true); 

また、あなたは、クライアントとサーバーで同じポートを使用しないでください!

第2に、あなたは「クローズ」戦略を持っていません。クライアントはいつジョブが完了したことを知っていると思いますか?どのようにしてスレッドが素人を終わらせるのを防ぐのですか? あなたが最後にこの

サーバ・ハンドラに

public class ServerHandler extends SimpleChannelHandler{ 

    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){ 
     byte[] resp=data.getBytes();//data is a String greater than 1024bytes; 
     ChannelBuffer buffer=ChannelBuffers.buffer(resp.length); 
     buffer.writerBytes(resp); 
     e.getChannel().write(buffer); 
     buffer.clear(); 
     e.getChannel.close(); 
    } 
} 

CLIENTブートストラップ

public class Client{ 
    public static void main(String[] args){ 
     ChannelFactory channelFactory=new NioClientSocketChannelFactory(
      Executors.newCachedThreadPool(), 
      Executors.newCachedThreadPool()); 
     ClientBootstrap bootstrap=new ClientBootstrap(channelFactory); 
     bootstrap.getPipeline().addLast("handler", new PhoneClientHandler()); 

     bootstrap.setOption("child.tcpNoDelay", true); 
     bootstrap.setOption("child.keepAlive", true); 

     // Start the connection attempt. 
     ChannelFuture future = bootstrap.connect(new InetSocketAddress("127.0.0.1",8181)); 

     // Wait until the connection is closed or the connection attempt fails. 
     future.getChannel().getCloseFuture().awaitUninterruptibly(); 

     // Shut down thread pools to exit. 
     bootstrap.releaseExternalResources(); 
    } 
} 

を行う必要があり、あなたは例の多くを読み取ることによって、あなたは何をしているかをよりよく理解する必要があります。それらは、org.jboss.netty.exampleパッケージの中にあり、バンドルされています。

+0

ありがとう、私はそれを見つけ出す!ありがとうございました ! – Gofier

3

ClientHandlerにチャネルバッファの代わりにTruncatedChannelBufferまたはBigEndianHeapChannelBufferを試してください。私はそれが動作すると思う..またはそれが動作しない場合は、親切に生成された例外のstacktraceを投稿してください。私は私のコードでこれを試して、それは働いた..これがあなたを助けてくれることを願っています。

public void messageReceived(ChannelHandlerContext channelHandlerContext,MessageEvent messageEvent) throws Exception { 

    Object messageObject = messageEvent.getMessage(); 

    // if size of message < 1024 then TruncatedChannelBuffer is returned. 

    if (messageObject instanceof TruncatedChannelBuffer) { 

     try { 

      TruncatedChannelBuffer truncatedChannelBuffer = (TruncatedChannelBuffer) messageObject; 

      byte[] byteArray = new byte[truncatedChannelBuffer.readableBytes()]; 

      truncatedChannelBuffer.readBytes(byteArray); 

      System.out.print(" Message = "+new String(byteArray)); 

      truncatedChannelBuffer.clear(); 

     } catch (Exception e) { 

      System.out.println("Exception in MessageReceived..."); 

      e.printStackTrace(); 


     } 
    } 
    // if size of message > 1024 then BigEndianHeapChannelBuffer is returned. 

    if (messageObject instanceof BigEndianHeapChannelBuffer) { 

     try { 

      BigEndianHeapChannelBuffer bigEndianHeapChannelBuffer = (BigEndianHeapChannelBuffer) messageObject; 

      byte[] byteArray = new byte[bigEndianHeapChannelBuffer.readableBytes()]; 

      bigEndianHeapChannelBuffer.readBytes(byteArray); 

      System.out.print(" Message = "+new String(byteArray)); 

      bigEndianHeapChannelBuffer.clear(); 


     } catch (Exception e) { 

      System.out.println("Exception in MessageReceived..."); 

      e.printStackTrace(); 

     } 
    } 

}  
1

RenaudBlue @は良いポイントになります。また、私はすべてのByteBufsがダイナミックになりNetty4、への切り替えを提案し、そのチャンク作る/管理するより簡単に読み書きを行う。"Porting the client"を参照してください。例えば

private void sendNumbers() { 
    // Do not send more than 4096 numbers. 
    boolean finished = false; 
    MessageBuf<Object> out = ctx.nextOutboundMessageBuffer(); 
    while (out.size() < 4096) { 
     if (i <= count) { 
      out.add(Integer.valueOf(i)); 
      i ++; 
     } else { 
      finished = true; 
      break; 
     } 
    } 

    ChannelFuture f = ctx.flush(); 
    if (!finished) { 
     f.addListener(numberSender); 
    } 
} 

private final ChannelFutureListener numberSender = new ChannelFutureListener() { 
    @Override 
    public void operationComplete(ChannelFuture future) throws Exception { 
     if (future.isSuccess()) { 
      sendNumbers(); 
     } 
    } 
}; 

Netty4も"child.tcpNoDelay" ERROを妨げていたチャネルオプションの設定のための型の安全性を、持っていますr。

しかし、Netty4にとって大きな勝利は明確に定義されたスレッドモデルであり、Netty は多くの場合、が使いやすくなります。

0

あなたは次のようにchildHandler()SocketChannelのセットアップFixedRecvByteBufAllocatorする必要があります:私は質問を理解していない

bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { 
      @Override 
      protected void initChannel(SocketChannel ch) throws Exception { 
       ch.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(2 * 1024)); 
       ChannelPipeline pipeline = ch.pipeline(); 
       pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 5)); 
       pipeline.addLast(new StringEncoder()); 
       pipeline.addLast(new StringDecoder()); 
       ... 
      } 
     }); 
関連する問題