Skip navigation links

Package io.vertx.core.streams

There are several objects in Vert.x that allow items to be read from and written.

See: Description

Package io.vertx.core.streams Description

There are several objects in Vert.x that allow items to be read from and written. In previous versions the io.vertx.core.streams package was manipulating Buffer objects exclusively. From now, streams are not anymore coupled to buffers and work with any kind of objects.

In Vert.x, calls to write item return immediately and writes are internally queued.

It’s not hard to see that if you write to an object faster than it can actually write the data to its underlying resource then the write queue could grow without bound - eventually resulting in exhausting available memory.

To solve this problem a simple flow control capability is provided by some objects in the Vert.x API.

Any flow control aware object that can be written-to implements ReadStream, and any flow control object that can be read-from is said to implement WriteStream.

Let’s take an example where we want to read from a ReadStream and write the data to a WriteStream.

A very simple example would be reading from a NetSocket on a server and writing back to the same NetSocket - since NetSocket implements both ReadStream and WriteStream, but you can do this between any ReadStream and any WriteStream, including HTTP requests and response, async files, WebSockets, etc.

A naive way to do this would be to directly take the data that’s been read and immediately write it to the NetSocket, for example:

{@link examples.StreamsExamples#pump1(io.vertx.core.Vertx)}

There’s a problem with the above example: If data is read from the socket faster than it can be written back to the socket, it will build up in the write queue of the NetSocket, eventually running out of RAM. This might happen, for example if the client at the other end of the socket wasn’t reading very fast, effectively putting back-pressure on the connection.

Since NetSocket implements WriteStream, we can check if the WriteStream is full before writing to it:

{@link examples.StreamsExamples#pump2(io.vertx.core.Vertx)}

This example won’t run out of RAM but we’ll end up losing data if the write queue gets full. What we really want to do is pause the NetSocket when the write queue is full. Let’s do that:

{@link examples.StreamsExamples#pump3(io.vertx.core.Vertx)}

We’re almost there, but not quite. The NetSocket now gets paused when the file is full, but we also need to unpause it when the write queue has processed its backlog:

{@link examples.StreamsExamples#pump4(io.vertx.core.Vertx)}

And there we have it. The drainHandler(io.vertx.core.Handler<java.lang.Void>) event handler will get called when the write queue is ready to accept more data, this resumes the NetSocket which allows it to read more data.

It’s very common to want to do this when writing Vert.x applications, so we provide a helper class called Pump which does all this hard work for you. You just feed it the ReadStream and the WriteStream and it tell it to start:

{@link examples.StreamsExamples#pump5(io.vertx.core.Vertx)}

Which does exactly the same thing as the more verbose example.

Let’s look at the methods on ReadStream and WriteStream in more detail:

ReadStream

ReadStream is implemented by HttpClientResponse, DatagramSocket, HttpClientRequest, HttpServerFileUpload, HttpServerRequest, HttpServerRequestStream, MessageConsumer, NetSocket, NetSocketStream, WebSocket, WebSocketStream, TimeoutStream, AsyncFile.

Functions:

WriteStream

WriteStream is implemented by HttpClientRequest, HttpServerResponse WebSocket, NetSocket, AsyncFile, PacketWritestream and MessageProducer

Functions:

Pump

Instances of Pump have the following methods:

A pump can be started and stopped multiple times.

When a pump is first created it is not started. You need to call the start() method to start it.

Author:
<a href="mailto:[email protected]">Julien Viet</a>
Skip navigation links

Copyright © 2014. All Rights Reserved.