6.93. kink/socket/TCP¶
Provides stream based connecting sockets.
Example
The following program spawns a TCP/IP server and a client. The client sets socket options TCP_NODELAY, SO_SNDBUF, and SO_LINGER, then sends bytes [1, 2, 3] to the server.
:TCP.require_from('kink/socket/')
:TCP_SERVER.require_from('kink/socket/')
:IP.require_from('kink/socket/')
:IP_PORT.require_from('kink/socket/')
:THREAD.require_from('kink/thread/')
:BIN.require_from('kink/')
:CONTROL.require_from('kink/')
:spawn_client <- {(:Server_addr)
THREAD.spawn_io{
CONTROL.with_finally{(:finally)
:Tcp = TCP.open
finally{ Tcp.close }
# initial socket options
stdout.print_line(Tcp.tcp_nodelay.load.repr) # => false
stdout.print_line(Tcp.so_sndbuf.load.repr) # => 8192 (initial values vary for systems)
stdout.print_line(Tcp.so_linger.load.repr) # => []
# set socket options
Tcp.tcp_nodelay <- true
Tcp.so_sndbuf <- 1024
Tcp.so_linger <- [10]
stdout.print_line(Tcp.tcp_nodelay.load.repr) # => true
stdout.print_line(Tcp.so_sndbuf.load.repr) # => 2304 (the value was adjusted)
stdout.print_line(Tcp.so_linger.load.repr) # => [10]
Tcp.connect(Server_addr)
:Out = Tcp.output
finally{ Out.close }
Out.write(BIN.of(1))
Out.write(BIN.of(2))
Out.write(BIN.of(3))
}
}
}
CONTROL.with_finally{(:finally)
:Server = TCP_SERVER.open
finally{ Server.close }
Server.bind_listen(IP_PORT.new(IP.for_hostname('::1') 0))
:Server_addr = Server.local_address
spawn_client(Server_addr)
:Tcp = Server.accept
finally{ Tcp.close }
:In = Tcp.input
finally{ In.close }
:Bin = In.read_all
stdout.print_line(Bin.repr) # => (bin 0x01 0x02 0x03)
}
6.93.1. type tcp¶
`tcp` is a stream-based connecting socket. The protocol can be either TCP/IP, or stream based Unix domain socket.
6.93.1.1. Tcp.connect(Remote ...[$config={}])¶
`connect` tries to connect this socket to the remote address specified by `Remote`.
Config methods:
• C.on_success($success): default = {}
• C.on_error($error): default = {(:Exc) Exc.raise }
• C.on_closed($closed): default = a thunk which tail-calls $error
`connect` waits until connection is established, the socket is closed, or an IO error occurs.
If connection is established, `connect` tail-calls $success with no arg. The client can read data from, or write data to the socket.
If the connecting socket is closed, before or during invocation of `connect`, `connect` tail-calls $closed with no arg.
If an IO error occurs, `connect` closes the connecting socket and tail-calls $error with an `exception`.
Timeout
Connection timeout can be implemented using C.on_closed and Tcp.close_unless_connected.
:TCP.require_from('kink/socket/')
:IP.require_from('kink/socket/')
:IP_PORT.require_from('kink/socket/')
:THREAD.require_from('kink/thread/')
:CONTROL.require_from('kink/')
:PROCESS.require_from('kink/')
CONTROL.with_finally{(:finally)
:Tcp = TCP.open
finally{ Tcp.close }
# a blackhole address. see RFC 6666
:Blackhole = IP_PORT.new(IP.for_hostname('0100::1234') 8080)
# times out connection after 10 seconds
THREAD.spawn_io{
THREAD.sleep(10)
Tcp.close_unless_connected
}
# exits the process when connection times out
Tcp.connect(Blackhole){(:C)
C.on_closed{
stderr.print_line('connection time out')
PROCESS.exit(76)
}
}
}
# => connection time out
Note that the runtime or the operating system might also time out connection. In that case, an IO error might occur, rather than tail-calling $closed.
Preconditions
`Remote` must be a `socket_address`. It must match th protocol family of the socket.
$success must be a thunk.
$error must be a function which takes an `exception`.
$closed must be a thunk.
6.93.1.2. Tcp.bind(Local ...[$config])¶
`bind` binds a local address specified by `Local` to the socket.
Config methods:
• C.on_success($success): default = {}
• C.on_error($error): default = {(:Exc) Exc.raise }
If the address is successfully bound, `bind` tail-calls $success with no arg.
If an IO error occurs, `bind` tail-calls $error with an `exception`.
Preconditions
`Local` must be a `socket_address`, whose protocol family matches one of the socket.
$success must be a thunk.
$error must be a function which takes an `exception`.
6.93.1.3. Tcp.close(...[$config={}])¶
`close` closes the connecting socket.
Config methods:
• C.on_success($success): default = {}
• C.on_error($error): default = {(:Exc) Exc.raise }
If the socket is closed successfully, `close` tail-calls $success with no arg.
If an IO error occurs, `close` tail-calls $error with an `exception`.
Preconditions
$success must be a thunk.
$error must be a function which takes an `exception`.
6.93.1.4. Tcp.close_unless_connected(...[$config={}])¶
`close_unless_connected` closes the connecting socket if and only if the socket is not yet connected. If the socket is connected, or already closed, `close_unless_connected` does nothing.
Config methods:
• C.on_success($success): default = {}
• C.on_error($error): default = {(:Exc) Exc.raise }
If the socket is connected, or already closed, `close_unless_connected` tail-calls $success with no arg.
If the socket is not yet connected, `close_unless_connected` closes the socket. If it is successful, `close_unless_connected` tail-calls $success with no arg. If an IO error occurs, `close_unless_connected` tail-calls $error with an `exception`.
Preconditions
$success must be a thunk.
$error must be a function which takes an `exception`.
6.93.1.5. Tcp.input(...[$config={}])¶
`input` method makes an `input` of the connecting socket.
Config method:
• C.buffer(...[Max_buf_size])
If C.buffer is called, the result `input` will perform userspace buffering. If `Max_buf_size` is given, the buffer size will not exceed `Max_buf_size`. If C.buffer is not called, the result `input` will not perform userspace buffering.
Closing the `input` will shut down the input stream of the socket.
Precondition
`Max_buf_size` must be a positive integer `num`.
6.93.1.6. Tcp.output(...[$config={}])¶
`output` method makes an `output` of the connecting socket.
Config method:
• C.buffer(...[Max_buf_size])
If C.buffer is called, the result `output` will perform userspace buffering. If `Max_buf_size` is given, the buffer size will not exceed `Max_buf_size`. If C.buffer is not called, the result `output` will not perform userspace buffering.
Closing the output will shut down the output stream of the socket.
Precondition
`Max_buf_size` must be a positive integer `num`.
6.93.1.7. Tcp.local_address(...[$config={}])¶
`local_address` retrieves a `socket_address` of the local address of the connecting socket.
Config methods:
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = {(:Exc) Exc.raise }
If the local address is available, `local_address` tail-calls $success with the `socket_address`.
If an IO error occurs, `local_address` tail-calls $error with an `exception`.
Preconditions
$success must be a function which takes a `socket_address`.
$error must be a function which takes an `exception`.
6.93.1.8. Tcp.remote_address(...[$config={}])¶
`remote_address` retrieves a `socket_address` of the remote address of the connecting socket.
Config methods:
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = {(:Exc) Exc.raise }
If the remote address is available, `remote_address` tail-calls $success with the `socket_address`.
If an IO error occurs, `remote_address` tail-calls $error with an `exception`.
Preconditions
$success must be a function which takes a `socket_address`.
$error must be a function which takes an `exception`.
6.93.1.9. Tcp.tcp_nodelay¶
`tcp_nodelay` returns a `ref` of a `bool` of TCP_NODELAY option.
For usage of socket options, see the example program at the beginning of this module.
Precondition
The protocol family must be ipv4 or ipv6.
6.93.1.10. Tcp.so_keepalive¶
`so_keepalive` returns a `ref` of a `bool` of SO_KEEPALIVE option.
For usage of socket options, see the example program at the beginning of this module.
Precondition
The protocol family must be ipv4 or ipv6.
6.93.1.11. Tcp.so_reuseaddr¶
`so_reuseaddr` returns a `ref` of a `bool` of SO_REUSEADDR option.
For usage of socket options, see the example program at the beginning of this module.
Precondition
The protocol family must be ipv4 or ipv6.
6.93.1.12. Tcp.so_linger¶
`so_linger` returns an optional non-negative integer `num` of SO_LINGER option.
The value of the `ref` is either an empty `vec`, or a singleton `vec` [l_linger], where `l_linger` is a non-negative integer `num`. When the value is an empty `vec`, SO_LINGER option is turned off. When the value is a singleton `vec`, SO_LINGER option is turned on, with `l_linger` as the timeout seconds.
For usage of socket options, see the example program at the beginning of this module.
Precondition
The protocol family must be ipv4 or ipv6.
6.93.1.13. Tcp.so_sndbuf¶
`so_sndbuf` returns a `ref` of a non-negative integer `num` of SO_SNDBUF option.
For usage of socket options, see the example program at the beginning of this module.
6.93.1.14. Tcp.so_rcvbuf¶
`so_rcvbuf` returns a `ref` of a non-negative integer `num` of SO_RCVBUF option.
For usage of socket options, see the example program at the beginning of this module.
6.93.2. TCP.open(...[Protocol_family=PROTOCOL_FAMILY.ipv6 $config={}])¶
`open` makes a new connecting socket.
Config methods:
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = {(:Exc) Exc.raise }
• C.on_unsupported($unsupported): default = a function which tail-calls $error
If a socket is created, `open` tail-calls $success with a `tcp`.
If the specified protocol family is not supported by the runtime, `open` tail-calls $unsupported with no arg.
If an IO error occurs, `open` tail-calls $error with an `exception`.
Preconditions
Protocol_family must be a `protocol_family`.
$success must be a function which takes a `tcp`.
$error must be a function which takes an `exception`.
$unsupported must be a thunk.
6.93.3. TCP.is?(Val)¶
`is?` returns whether `Val` is a `tcp`.