Protocols
The following protocols are available globally.
-
The core
Channel
methods that are for internal use of theChannel
implementation only.Warning
If you are not implementing a custom
Channel
type, you should never call any of these.Note
All methods must be called from the
EventLoop
thread.Declaration
Swift
public protocol ChannelCore : AnyObject
-
A
Channel
is easiest thought of as a network socket. But it can be anything that is capable of I/O operations such as read, write, connect, and bind.Note
All operations onChannel
are thread-safe.In SwiftNIO, all I/O operations are asynchronous and hence all operations on
Channel
are asynchronous too. This means that all I/O operations will return immediately, usually before the work has been completed. TheEventLoopPromise
s passed to or returned by the operations are used to retrieve the result of an operation after it has completed.A
See moreChannel
owns itsChannelPipeline
which handles all I/O events and requests associated with theChannel
.Declaration
Swift
public protocol Channel : AnyObject, ChannelOutboundInvoker
-
Undocumented
See moreDeclaration
Swift
public protocol NIOSynchronousChannelOptions
-
You should never implement this protocol directly. Please implement one of its sub-protocols.
See moreDeclaration
Swift
public protocol ChannelHandler : AnyObject
-
Untyped
ChannelHandler
which handles outbound I/O events or intercept an outbound I/O operation.Despite the fact that
write
is one of the methods on thisprotocol
, you should avoid assuming that “outbound” events are to do with writing to channel sources. Instead, “outbound” events are events that are passed to the channel source (e.g. a socket): that is, things you tell the channel source to do. That includeswrite
(“write this data to the channel source”), but it also includesread
(“please begin attempting to read from the channel source”) andbind
(“please bind the following address”), which have nothing to do with sending data.We strongly advise against implementing this protocol directly. Please implement
See moreChannelOutboundHandler
.Declaration
Swift
public protocol _ChannelOutboundHandler : ChannelHandler
-
Untyped
ChannelHandler
which handles inbound I/O events.Despite the fact that
channelRead
is one of the methods on thisprotocol
, you should avoid assuming that “inbound” events are to do with reading from channel sources. Instead, “inbound” events are events that originate from the channel source (e.g. the socket): that is, events that the channel source tells you about. This includes things likechannelRead
(“there is some data to read”), but it also includes things likechannelWritabilityChanged
(“this source is no longer marked writable”).We strongly advise against implementing this protocol directly. Please implement
See moreChannelInboundHandler
.Declaration
Swift
public protocol _ChannelInboundHandler : ChannelHandler
-
A
RemovableChannelHandler
is aChannelHandler
that can be dynamically removed from aChannelPipeline
whilst theChannel
is operating normally. ARemovableChannelHandler
is required to remove itself from theChannelPipeline
(usingChannelHandlerContext.removeHandler
) as soon as possible.Note
When aChannel
gets torn down, everyChannelHandler
in theChannel
‘sChannelPipeline
will be removed from theChannelPipeline
. Those removals however happen synchronously and are not going through the methods of this protocol.Declaration
Swift
public protocol RemovableChannelHandler : ChannelHandler
-
Allows users to invoke an “outbound” operation related to a
See moreChannel
that will flow through theChannelPipeline
until it will finally be executed by the theChannelCore
implementation.Declaration
Swift
public protocol ChannelOutboundInvoker
-
Fire inbound events related to a
See moreChannel
through theChannelPipeline
until its end is reached or it’s consumed by aChannelHandler
.Declaration
Swift
public protocol ChannelInboundInvoker
-
A protocol that signals that outbound and inbound events are triggered by this invoker.
Declaration
Swift
public protocol ChannelInvoker : ChannelInboundInvoker, ChannelOutboundInvoker
-
Declaration
Swift
public protocol ChannelOption : Equatable
-
ByteToMessageDecoder
s decode bytes in a stream-like fashion fromByteBuffer
to another message type.Purpose
A
ByteToMessageDecoder
provides a simplified API for handling streams of incoming data that can be broken up into messages. This API boils down to two methods:decode
, anddecodeLast
. These two methods, when implemented, will be used by aByteToMessageHandler
paired with aByteToMessageDecoder
to decode the incoming byte stream into a sequence of messages.The reason this helper exists is to smooth away some of the boilerplate and edge case handling code that is often necessary when implementing parsers in a SwiftNIO
ChannelPipeline
. AByteToMessageDecoder
never needs to worry about how inbound bytes will be buffered, asByteToMessageHandler
deals with that automatically. AByteToMessageDecoder
also never needs to worry about memory exclusivity violations that can occur when re-entrantChannelPipeline
operations occur, asByteToMessageHandler
will deal with those as well.Implementing ByteToMessageDecoder
A type that implements
ByteToMessageDecoder
may implement two methods: decode and decodeLast. Implementations must implement decode: if they do not implement decodeLast, a default implementation will be used that simply calls decode.decode
is the main decoding method, and is the one that will be called most often.decode
is invoked whenever data is received by the wrappingByteToMessageHandler
. It is invoked with aByteBuffer
containing all the received data (including any data previously buffered), as well as aChannelHandlerContext
that can be used in thedecode
function.decode
is called in a loop by theByteToMessageHandler
. This loop continues until one of two cases occurs:- The input
ByteBuffer
has no more readable bytes (i.e..readableBytes == 0
); OR - The
decode
method returns.needMoreData
.
The reason this method is invoked in a loop is to ensure that the stream-like properties of inbound data are respected. It is entirely possible for
ByteToMessageDecoder
to receive either fewer bytes than a single message, or multiple messages in one go. Rather than have theByteToMessageDecoder
handle all of the complexity of this, the logic can be boiled down to a single choice: has theByteToMessageDecoder
been able to move the state forward or not? If it has, rather than containing an internal loop it may simply return.continue
in order to request thatdecode
be invoked again immediately. If it has not, it can return.needMoreData
to ask to be left alone until more data has been returned from the network.Essentially, if the next parsing step could not be taken because there wasn’t enough data available, return
.needMoreData
. Otherwise, return.continue
. This will allow aByteToMessageDecoder
implementation to ignore the awkward way data arrives from the network, and to just treat it as a series ofdecode
calls.decodeLast
is a cousin ofdecode
. It is also called in a loop, but unlike withdecode
this loop will only ever occur once: when theChannelHandlerContext
belonging to thisByteToMessageDecoder
is about to become invalidated. This invalidation happens in two situations: when EOF is received from the network, or when theByteToMessageDecoder
is being removed from theChannelPipeline
. The distinction between these two states is captured by the value ofseenEOF
.In this condition, the
ByteToMessageDecoder
must now produce any final messages it can with the bytes it has available. In protocols where EOF is used as a message delimiter, havingdecodeLast
called withseenEOF == true
may produce further messages. In other cases,decodeLast
may choose to deliver any buffered bytes as “leftovers”, either in error messages or viachannelRead
. This can occur if, for example, a protocol upgrade is occurring.As with
decode
,decodeLast
is invoked in a loop. This allows the same simplification asdecode
allows: when a message is completely parsed, thedecodeLast
function can return.continue
and be re-invoked from the top, rather than containing an internal loop.Note that the value of
seenEOF
may change between calls todecodeLast
in some rare situations.Implementers Notes
///
ByteToMessageHandler
will turn yourByteToMessageDecoder
into aChannelInboundHandler
.ByteToMessageHandler
also solves a couple of tricky issues for you. Most importantly, in aByteToMessageDecoder
you do not need to worry about re-entrancy. Your code owns the passed-inByteBuffer
for the duration of thedecode
/decodeLast
call and can modify it at will.If a custom frame decoder is required, then one needs to be careful when implementing one with
ByteToMessageDecoder
. Ensure there are enough bytes in the buffer for a complete frame by checkingbuffer.readableBytes
. If there are not enough bytes for a complete frame, return without modifying the reader index to allow more bytes to arrive.To check for complete frames without modifying the reader index, use methods like
buffer.getInteger
. You MUST use the reader index when using methods likebuffer.getInteger
. For example callingbuffer.getInteger(at: 0)
is assuming the frame starts at the beginning of the buffer, which is not always the case. Usebuffer.getInteger(at: buffer.readerIndex)
instead.If you move the reader index forward, either manually or by using one of
buffer.read*
methods, you must ensure that you no longer need to see those bytes again as they will not be returned to you the next timedecode
is called. If you still need those bytes to come back, consider taking a local copy of buffer inside the function to perform your read operations on.The
ByteBuffer
passed in asbuffer
is a slice of a larger buffer owned by theByteToMessageDecoder
implementation. Some aspects of this buffer are preserved across calls todecode
, meaning that any changes to those properties you make in yourdecode
method will be reflected in the next call to decode. In particular, moving the reader index forward persists across calls. When your method returns, if the reader index has advanced, those bytes are considered “consumed” and will not be available in future calls todecode
. Please note, however, that the numerical value of thereaderIndex
itself is not preserved, and may not be the same from one call to the next. Please do not rely on this numerical value: if you need to recall where a byte is relative to thereaderIndex
, use an offset rather than an absolute value.Using ByteToMessageDecoder
To add a
ByteToMessageDecoder
to theChannelPipeline
use
See morechannel.pipeline.addHandler(ByteToMessageHandler(MyByteToMessageDecoder()))
Declaration
Swift
public protocol ByteToMessageDecoder
- The input
-
Some
ByteToMessageDecoder
s need to observewrite
s (which are outbound events).ByteToMessageDecoder
s which implement theWriteObservingByteToMessageDecoder
protocol will be notified about every outbound write.
See moreWriteObservingByteToMessageDecoder
may only observe awrite
and must not try to transform or block it in any way. After thewrite
method returns thewrite
will be forwarded to the next outbound handler.Declaration
Swift
public protocol WriteObservingByteToMessageDecoder : ByteToMessageDecoder
-
A protocol for straightforward encoders which encode custom messages to
See moreByteBuffer
s. To add aMessageToByteEncoder
to aChannelPipeline
, usechannel.pipeline.addHandler(MessageToByteHandler(myEncoder)
.Declaration
Swift
public protocol MessageToByteEncoder
-
See moreNIOClientTCPBootstrapProtocol
is implemented by various underlying transport mechanisms. Typically, this will be the BSD Sockets API implemented byClientBootstrap
.Declaration
Swift
public protocol NIOClientTCPBootstrapProtocol
-
An EventLoop processes IO / tasks in an endless loop for
Channel
s until it’s closed.Usually multiple
Channel
s share the sameEventLoop
for processing IO / tasks and so share the same processingNIOThread
. For a better understanding of how such anEventLoop
works internally the following pseudo code may be helpful:while eventLoop.isOpen { /// Block until there is something to process for 1...n Channels let readyChannels = blockUntilIoOrTasksAreReady() /// Loop through all the Channels for channel in readyChannels { /// Process IO and / or tasks for the Channel. /// This may include things like: /// - accept new connection /// - connect to a remote host /// - read from socket /// - write to socket /// - tasks that were submitted via EventLoop methods /// and others. processIoAndTasks(channel) } }
Because an
See moreEventLoop
may be shared between multipleChannel
s it’s important to NOT block while processing IO / tasks. This also includes long running computations which will have the same effect as blocking in this case.Declaration
Swift
public protocol EventLoop : EventLoopGroup
-
Declaration
Swift
public protocol EventLoopGroup : AnyObject
-
Undocumented
See moreDeclaration
Swift
public protocol FileDescriptor
-
Allocates
See moreByteBuffer
s to be used to read bytes from aChannel
and records the number of the actual bytes that were used.Declaration
Swift
public protocol RecvByteBufferAllocator
-
A simplified version of
ByteToMessageDecoder
that can generate zero or one messages for each invocation ofdecode
ordecodeLast
. Havingdecode
anddecodeLast
return an optional message avoids re-entrancy problems, since the functions relinquish exclusive access to theByteBuffer
when returning. This allows for greatly simplified processing.Many
See moreByteToMessageDecoder
‘s can trivially be translated toNIOSingleStepByteToMessageDecoder
’s. You should not implementByteToMessageDecoder
’s decodeand
decodeLast` methods.Declaration
Swift
public protocol NIOSingleStepByteToMessageDecoder : ByteToMessageDecoder
-
This protocol defines an object, most commonly a
Channel
, that supports setting and getting socket options (viasetsockopt
/getsockopt
or similar). It provides a strongly typed API that makes working with larger, less-common socket options easier than theChannelOption
API allows.The API is divided into two portions. For socket options that NIO has prior knowledge about, the API has strongly and safely typed APIs that only allow users to use the exact correct type for the socket option. This will ensure that the API is safe to use, and these are encouraged where possible.
These safe APIs are built on top of an “unsafe” API that is also exposed to users as part of this protocol. The “unsafe” API is unsafe in the same way that
UnsafePointer
is: incorrect use of the API allows all kinds of memory-unsafe behaviour. This API is necessary for socket options that NIO does not have prior knowledge of, but wherever possible users are discouraged from using it.Relationship to SocketOption
All
Channel
objects that implement this protocol should also support theSocketOption
ChannelOption
for simple socket options (those with Cint
values). These are the most common socket option types, and so thisChannelOption
represents a convenient shorthand for using this protocol where the type allows, as well as avoiding the need to cast to this protocol.Note
Like theChannel
protocol, all methods in this protocol are thread-safe.Declaration
Swift
public protocol SocketOptionProvider
-
ChannelHandler which will emit data by calling
ChannelHandlerContext.write
.We strongly advice against implementing this protocol directly. Please implement
See moreChannelInboundHandler
or / andChannelOutboundHandler
.Declaration
Swift
public protocol _EmittingChannelHandler
-
ChannelHandler
which handles inbound I/O events for aChannel
.Please refer to
See more_ChannelInboundHandler
and_EmittingChannelHandler
for more details on the provided methods.Declaration
Swift
public protocol ChannelInboundHandler : _ChannelInboundHandler, _EmittingChannelHandler
-
ChannelHandler
which handles outbound I/O events or intercept an outbound I/O operation for aChannel
.Please refer to
See more_ChannelOutboundHandler
and_EmittingChannelHandler
for more details on the provided methods.Declaration
Swift
public protocol ChannelOutboundHandler : _ChannelOutboundHandler, _EmittingChannelHandler
-
Undocumented
See moreDeclaration
Swift
public protocol NIOClientTLSProvider