Note that there are some explanatory texts on larger screens.

plurals
  1. POAssembling a Netty Message in the Handler
    primarykey
    data
    text
    <p>I am in the process of prototyping Netty for my project. I am trying to implement a simple Text/String oriented protocol on top of Netty. In my pipeline I am using the following:</p> <pre><code>public class TextProtocolPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Add the text line codec combination first, pipeline.addLast("framer", new DelimiterBasedFrameDecoder(2000000, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); // and then business logic. pipeline.addLast("handler", new TextProtocolHandler()); return pipeline; } } </code></pre> <p>I have a DelimiterBasedFrameDecoder, a String Decoder, and a String Encoder in the pipeline.</p> <p>As a result of this setup my incoming message is split into multiple Strings. This results in multiple invocations of the "messageReceived" method of my handler. This is fine. However , this requires me to accumulate these messages in memory and re-construct the message when the last string packet of the message is received.</p> <p>My question is, what is the most memory efficient way to "accumulate the strings" and then "re-construct them into the final message". I have 3 options so far. They are:</p> <ul> <li><p>Use a StringBuilder to accumulate and toString to construct. (This gives the worst memory performance. In fact for large payloads with lots of concurrent users this gives non-acceptable performance)</p></li> <li><p>Accumulate into a ByteArray via a ByteArrayOutputStream and then construct using the byte-array (this gives a much better performance than option 1, but it still hogs quite a bit of memory)</p></li> <li><p>Accumulate into a Dymamic Channel Buffer and use toString(charset) to construct. I have not profiled this setup yet but I am curious how this compares to the above two options. Has anyone solved this issue using the Dynamic Channel Buffer?</p></li> </ul> <p>I am new to Netty and its possible I may be doing something wrong architecturally. Your input will be greatly appreciated.</p> <p>Thanks in advance Sohil</p> <p><strong>Adding my implementation of a custom FrameDecoder for Norman to review</strong></p> <pre><code>public final class TextProtocolFrameDecoder extends FrameDecoder { public static ChannelBuffer messageDelimiter() { return ChannelBuffers.wrappedBuffer(new byte[] {'E','O','F'}); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel,ChannelBuffer buffer) throws Exception { int eofIndex = find(buffer, messageDelimiter()); if(eofIndex != -1) { ChannelBuffer frame = buffer.readBytes(buffer.readableBytes()); return frame; } return null; } private static int find(ChannelBuffer haystack, ChannelBuffer needle) { for (int i = haystack.readerIndex(); i &lt; haystack.writerIndex(); i ++) { int haystackIndex = i; int needleIndex; for (needleIndex = 0; needleIndex &lt; needle.capacity(); needleIndex ++) { if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) { break; } else { haystackIndex ++; if (haystackIndex == haystack.writerIndex() &amp;&amp; needleIndex != needle.capacity() - 1) { return -1; } } } if (needleIndex == needle.capacity()) { // Found the needle from the haystack! return i - haystack.readerIndex(); } } return -1; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload