Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

in netty, we can only write and receive data less than 1024bytes: how we can write or receive more?

Tags:

netty

When writing 2048bytes in on handler, the messageRevieved method should be called twice to receive the all data... how I can receive the 2048bytes data in

Code

Server:

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

Server Handler:

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

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

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

Client Handler:

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.
    }
}
like image 326
Gofier Avatar asked Apr 16 '12 08:04

Gofier


1 Answers

Well you can always decide how many bytes to write at a time, but you definitely never know when and how many bytes are received (this is why NIO makes sense). You need to handle you own buffer for receiving a fix number of bytes you want. To do so you can use a FrameDecoder which is design for this purpose.

Additionaly, you can make sure the datas does not stay too long in the sender socket buffer by setting tcpNoDelay to true, so it will no wait for the current "frame" to reach a certain critical size before physically sending the datas.

If I understand well, you are writing let's say 2048 Bytes in one hand but all the datas are not received in the messagedReceived event on the other hand? Try to check these common issues:

  • you application terminates too early and the datas are not yet arrived
  • your datas are stucked in the socket buffer of the "sender" because you did not close the Channel and tcpNoDelay option was not set to true. This is causing the socket to wait for some additional bytes before sending the packet.
  • you did not read all the datas inside the ChannelBuffer but for a reason the readerIndex as been set to a further position

Try to show us some part of your code, it should make things easier...

ADDED 17/04/2012

If I understand you are trying to pass a byte array coding for a String from the sender to the receiver. Here is your code after a littel refactor:

----------------------------code ----------------------------write hand: response.size()>1024bytes

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

----------------------------recieve hand: should recieve twice,println() would execute twice

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

This is not the way to do that, you should instead use directly the StringEncoder and StringDecoder in the package org.jboss.netty.handler.codec.string. It will handle the Framing problem for you. If you still want to debug your code, use the LoggingHandler provided by Netty. Also did you really set this option:

bootstrap.setOption("tcpNoDelay", true);

in both sides bootstraps?

like image 177
Renaud Avatar answered Oct 21 '22 14:10

Renaud