Unable to get long String message complete

48 views
Skip to first unread message

Mohd rully k

unread,
Mar 31, 2017, 12:27:43 AM3/31/17
to Netty discussions
Hii , first sorry if my post in the wrong place , I'm newbie and my English not good . So , i have project that require to read socket from coldfusion 7 , and I have succeed using standard thread and port listening . Now I'm try using netty for best speed and response .

This is my listener ,

public class NettyListener {

private final int port;

public NettyListener(int port) {
this.port = port;
}

public void start() throws Exception {
NioEventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new NettyHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
;

ChannelFuture f = b.bind().sync();
// System.out.println(NettyListener.class.getName()
// + " started and listen on " + f.channel().localAddress());
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}

and this is my handler 
@Sharable
public class NettyHandler extends ChannelInboundHandlerAdapter {

private static String raw;
String inputLine = null;

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
inputLine = in.toString(CharsetUtil.UTF_8);
int u = 1;
String lines[] = inputLine.split("[\\r\\n]+");
for (String i : lines) {
if (u == 6) { //this where data place normally 
String converT;
converT = i.replace("%20", " ").replace("%2E", ".")
.replace("%2F", "/").replace("%2D", "-")
.replace("%40", "@").replace("%2B", "+")
.replace("%28", "(").replace("%29", ")")
.replace("%2C", ",").replace("%5F", "_");
setRaw(converT);
}
u++;
}
// ctx.write(in);
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}

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

public static String getRaw() {
return raw;
}

public void setRaw(String raw) {
NettyHandler.raw = raw;
}

}


The problem is when data/message to long, the data will split into 2 object or more . Is there a way to compact this data/message becoming 1 String java . 

Thank in advance 

Regards 

Rully

Zhu Ran

unread,
Apr 1, 2017, 7:05:53 AM4/1/17
to Netty discussions
Netty inside will use a piece of buffer to provide data for you when you read data from channel.

The size of buffer is dynamic. Netty will change the size of buffer in this way:

1.the initial size would be small.
2.every time after you read the channel (means you read data from buffer),netty records the 
size of readable bytes in the buffer
3.if the size of readable bytes is less that the value of last time, netty would do nothing with
the size of the buffer, because netty think you have read all data you need, and wait you
reading again;
4.if the size of readable bytes equals to the value of last time, netty would enlarge the size of
the buffer and fill it with data, because netty notices that you have the chance to read the data
but you didn't read data, netty guess you want more data, so netty enlarge the buffer and fill
with more fresh data.

So, what you would actually do is not to read from the buffer if the 
readableBytes is less than you want.

there are two scenarios:
1) the size of the data you want is a constant value:
   In this scenario, you just compare the readableBytes to the constant
   value. if the data is not enough, you do nothing, just return; if the data
   is enough, you read it and do what you want

2)the size of the data you want is encoded in the fist several bytes of data( just as many
   protocal)
   you can use FixedLengthFrameDecoder to do the stuff.
   if FixedLengthFrameDecoder is not satisfied you, you can do some thing like that when
      reading the channel:
          a)mark the reader index
          b)read the first several bytes, and calculate the length of the data you want  
          c)if the readableBytes is enough, read it and do what you want
          d)if the readableBytes is not enough, reset the reader index(to tell netty that you don't read the data)

Talk is cheap, show you code.

A way to handle this is to use ByteToMessageDecoder.
Extend it and override ByteToMessageDecoder's decode method.

To solve scenario 1):


    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int LENGTH = 200000;
        if (in.readableBytes() < LENGTH)
                    return;
        else {
                    byte[] bytes = new byte[LENGTH];
                    in.readBytes(bytes , 0, LENGTH);
                    //do stuff...
        }
    }


To solve scenario 2):

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        int LENGTH_SIZE = 4;
        byte[] lengthBytes = new byte[LENGTH_SIZE ];
        in.markReaderIndex().readBytes(lengthBytes, 0, LENGTH_SIZE );
        int length = Bits.toInt(lengthBytes);
        if (in.readableBytes() >= length) {
            byte[] content = new byte[length];
            in.readBytes(content, 0, length);
            //do some stuff
        } else {
            in.resetReaderIndex();
        }
    }

Mohd rully k

unread,
Apr 1, 2017, 1:01:32 PM4/1/17
to Netty discussions
Hi Mr.Zhu 

What a excellent explanation and thank you very much for your time . I think I prefer scenario 2 , and need study more and try that . Once again thank you 
Reply all
Reply to author
Forward
0 new messages