2 Transports
(require net2/transport) | package: net2 |
A transport is a means of reliably sending and receiving bytes between two named parties across some network. TCP connections over an IP network serve as a canonical example, with the two parties named by their IP addresses and port numbers. A transport pairs an input port and an output port with two authorities: one naming the party using those ports, and one naming the party "on the other end" of the connection. Transports can be directly constructed from ports with transport.
Transports do not have a notion of clients and servers —
Transports are not thread safe in the sense that two threads attempting to serialize and deserialize complex messages directly to the same transport will interleave their bytes on the wire, leading to mangled and uninterpretable messages. To prevent threads from concurrently writing messages without opening multiple transports between the same authorities, use a dedicated thread for serializing and deserializing messages from a message buffer which other threads read and write messages to atomically instead of sharing the connection directly.
2.1 Transport Primitives
procedure
(transport #:in in #:out out #:source source #:dest dest) → transport? in : input-port? out : output-port? source : authority? dest : authority?
procedure
(transport-in trans) → input-port?
trans : transport?
procedure
(transport-out trans) → output-port?
trans : transport?
procedure
trans : transport?
procedure
trans : transport?
2.2 Transport Cleanup and Disposables
The transport API does not offer any means of directly overriding how a transport is shut down except for making custom ports that perform special cleanup actions when closed. Broadly, this is because there are only two kinds of cleanup actions one might want to perform on a transport:
System cleanup actions that free local operating system resources, such as releasing file descriptors associated with the input and output ports.
Connection cleanup actions that send messages to the transport’s destination authority in an attempt to negotiate a graceful connection termination, such as TCP’s use of FIN packets.
System cleanup actions are usually associated directly with a single
input port or output port —
Connection cleanup actions involve coordination and communication with another party over a network. Connection cleanup is inherently unreliable. There is no way to guarantee that communication with the other party won’t abrubtly terminate at any point. Therefore, connection cleanup should be performed on a best effort basis that tolerates failure. It is inappropriate to perform connection cleanup actions during a custodian shutdown using ffi/unsafe/custodian, because custodian shutdowns are performed unsafely and expected to always succeed with very little (if any) IO.
To properly implement connection cleanup actions in transports, many interfaces in net2 require that connection cleanup logic is encapsulated in a disposable from the disposable library. This allows declaratively specifying how and when connection termination logic will execute, and reduces the complexity involved in adding timeout and early termination logic. See tcp-connector for an example of constructing transports with robust and graceful connection termination. Alternatively, refer to connectors and listeners for information on how they encapsulate connection termination with disposables and custodians.