0

I noticed it is possible to eother write data which is an instance of ByteBuff or plain Java Objects when using Netty.

As can be seen in the HAProxyClient

On that file you have

HAProxyMessage message = new HAProxyMessage(
                    HAProxyProtocolVersion.V2, 
                    HAProxyCommand.PROXY, HAProxyProxiedProtocol.TCP4,
                    "127.0.0.1", 
                    "127.0.0.2", 
                    8000, 
                    9000
);

ch.writeAndFlush(message).sync();

Where a normal Java object, HAProxyMessage was written to the context. Still on the same file, you have:

ch.writeAndFlush(Unpooled.copiedBuffer("Hello World!", CharsetUtil.US_ASCII)).sync();

Where Unpooled.copiedBuffer is used to create the data to be written. This method returns a ByteBuf.

The question then is: what is the material difference (if any) between writing (or reading) a plan Java object and a ByteBuf

Finlay Weber
  • 2,989
  • 3
  • 17
  • 37

1 Answers1

2

When you write a ByteBuf, the message does not need any conversion. When it is a Java Object, you need an encoder/decoder. Here you have the following:

They transform the Java Object to ByteBuf (Encoder) or reversely (Decoder).

The way you want to use one or the other depends on you current case:

  • do you managed Java Object? Probably having a codec (Encoder/Decodec) is a good way.
  • do you maneged simple data (bytestream, simple values...)? Probably managing directly ByteBuf is a good way. These are not the only relevant questions to decide for one or the other.

But finally, in Netty, everything is a ByteBuf.

Frederic Brégier
  • 2,108
  • 1
  • 18
  • 25
  • I see. Hence if I need to say write something like a newline. Turning that to a byte[] array would probably be more efficient than wrapping it in a ByteBuf? or not? – Finlay Weber Feb 27 '21 at 14:43
  • The huge advantage of ByteBuf is its ability to cumulate various sources. For instance, from a byte array, using wrapped ByteBuf, and to add some bytes, using a composite ByteBuf, or reverseley to create a ByteBuf with the probable final size and write everything into it. The main idea is to limit as much as possible memory copy, son in general, wrapping and using composition of ByteBufs are the best. But generally means also there are exceptions of course. Internally, Netty needs ByteBuf, so whatever the Java Object you use (even byte array) would have to turn to ByteBuf finally. – Frederic Brégier Feb 27 '21 at 14:53
  • Thanks for the response. I know there are different implementation of ByteBuf. Do you by chance know the default one Netty uses internally...so example in a case where something as simple as byte[] is being written? – Finlay Weber Feb 27 '21 at 14:58
  • It really depends on the protocol. For instance, when the size is already known and the message is built from various sources, the ByteBuf is allocated once and written from various sources (this tend to have continuous internal byte array, so more efficient but at the price of multiple copies). Another example is when the source is limited to one byte array (or more, as in your example), to prevent copy, we use wrappedBuffers(array1, array2, array3), which tends to limit copy at the price to not contiguous memory access. However, finally, everything needs to be ByteBuf. – Frederic Brégier Feb 27 '21 at 15:13
  • Additionnaly, Netty uses a powerful and efficient algorithm for memory allocation, reusing, buffering, so the reason of the ByteBuf. If you have only one byte array (or 2, one for the real data, another one, fixed, for "\n".getBytes(), you could use wrappedBuffers. But if you have the possibility to build this byte array directly into a ByteBuf, it could be even better, since "your" byte array is therefore not managed by the memory pool of Netty when wrapping it. – Frederic Brégier Feb 27 '21 at 15:25
  • Also beside this a byte[] can not written directly to the socket as you need to have “direct/native memory” for this which is not allocated on the heap. – Norman Maurer Feb 27 '21 at 18:24