std.net.socket.Socket
type pub SocketA low-level, non-blocking IPv4 or IPv6 socket.
Static methods
datagram
Show source codeHide source code
fn pub static datagram(ipv6: Bool) -> Result[Socket, Error] {
Socket.new(ipv6, libc.SOCK_DGRAM, protocol: 0)
}fn pub static datagram(ipv6: Bool) -> Result[Socket, Error]Returns a new Socket configured as a datagram socket.
The ipv6 argument specifies if the socket is an IPv4 socket (false) or
an IPv6 socket (true).
Examples
import std.net.socket (Socket)
Socket.datagram(ipv6: false)
raw
Show source codeHide source code
fn pub static raw(ipv6: Bool, protocol: Int) -> Result[Socket, Error] {
Socket.new(ipv6, libc.SOCK_RAW, protocol)
}fn pub static raw(ipv6: Bool, protocol: Int) -> Result[Socket, Error]Returns a new Socket configured as a raw socket.
The ipv6 argument specifies if the socket is an IPv4 socket (false) or
an IPv6 socket (true).
The protocol argument must specify a valid IANA IP protocol as defined in
RFC 1700.
Note that on certain platforms (e.g. Linux, and probably most other Unix systems) you'll need root privileges in order to create a raw socket.
Examples
import std.net.socket (Socket)
Socket.raw(ipv6: false, protocol: 1)
stream
Show source codeHide source code
fn pub static stream(ipv6: Bool) -> Result[Socket, Error] {
Socket.new(ipv6, libc.SOCK_STREAM, protocol: 0)
}fn pub static stream(ipv6: Bool) -> Result[Socket, Error]Returns a new Socket configured as a stream socket.
The ipv6 argument specifies if the socket is an IPv4 socket (false) or
an IPv6 socket (true).
Examples
import std.net.socket (Socket)
Socket.stream(ipv6: false)
Instance methods
accept
Show source codeHide source code
fn pub accept -> Result[Socket, Error] {
let peer = net.raw_socket
try sys.accept(@socket, mut peer, @deadline)
Result.Ok(Socket(socket: peer, deadline: net.NO_DEADLINE))
}fn pub accept -> Result[Socket, Error]Accepts a new incoming connection from this socket.
This method will not return until a connection is available.
Examples
Accepting a connection and reading data from the connection:
import std.net.socket (Socket)
import std.net.ip (IpAddress)
let listener = Socket.stream(ipv6: false).get
let stream = Socket.stream(ipv6: false).get
listener.bind(ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
listener.listen.get
stream.connect(ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
stream.write('ping').get
let client = listener.accept.get
let buffer = ByteArray.new
client.read(into: buffer, size: 4).get
buffer.to_string # => 'ping'
bind
Show source codeHide source code
fn pub mut bind(ip: IpAddress, port: Int) -> Result[Nil, Error] {
sys.bind_ip(@socket.inner, ip, port)
}fn pub mut bind(ip: IpAddress, port: Int) -> Result[Nil, Error]Binds this socket to the specified address.
Examples
Binding a socket:
import std.net.socket (Socket)
import std.net.ip (IpAddress)
let socket = Socket.datagram(ipv6: false).get
socket.bind(ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
broadcast=
Show source codeHide source code
fn pub mut broadcast=(value: Bool) -> Result[Nil, Error] {
set_option(libc.SOL_SOCKET, libc.SO_BROADCAST, value.to_int)
}fn pub mut broadcast=(value: Bool) -> Result[Nil, Error]Sets the value of the SO_BROADCAST option.
connect
Show source codeHide source code
fn pub mut connect(ip: IpAddress, port: Int) -> Result[Nil, Error] {
sys.connect_ip(@socket, ip, port, @deadline)
}fn pub mut connect(ip: IpAddress, port: Int) -> Result[Nil, Error]Connects this socket to the specified address.
Examples
Connecting a socket:
import std.net.socket (Socket)
import std.net.ip (IpAddress)
let listener = Socket.stream(ipv6: false).get
let client = Socket.stream(ipv6: false).get
socket.bind(ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
socket.listen.get
client.connect(ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
flush
Show source codeHide source code
fn pub mut flush -> Result[Nil, Error] {
Result.Ok(nil)
}fn pub mut flush -> Result[Nil, Error]Flushes any pending writes to the file system.
Flushing writes is a potentially expensive operation, and unnecessarily calling this method may degrade performance.
When flushing data to disk it's important to remember that the actual behaviour may vary based on the type of file system, operating system and storage hardware that's used. In particular, it's possible for one of these components to say "Yup, I totally flushed the data, you're all good!" when in fact they have not fully flushed the data.
keepalive=
Show source codeHide source code
fn pub mut keepalive=(value: Bool) -> Result[Nil, Error] {
set_option(libc.SOL_SOCKET, libc.SO_KEEPALIVE, value.to_int)
}fn pub mut keepalive=(value: Bool) -> Result[Nil, Error]Sets the value of the SO_KEEPALIVE option.
keepalive_interval=
Show source codeHide source code
fn pub mut keepalive_interval=(value: Duration) -> Result[Nil, Error] {
set_option(libc.IPPROTO_TCP, libc.TCP_KEEPINTVL, value.to_secs.to_int)
}fn pub mut keepalive_interval=(value: Duration) -> Result[Nil, Error]Sets the TCP keep-alive interval to the given value.
keepalive_time=
Show source codeHide source code
fn pub mut keepalive_time=(value: Duration) -> Result[Nil, Error] {
set_option(libc.IPPROTO_TCP, libc.TCP_KEEPIDLE, value.to_secs.to_int)
}fn pub mut keepalive_time=(value: Duration) -> Result[Nil, Error]Sets the TCP keep-alive time to the given value.
linger
Show source codeHide source code
fn pub linger -> Option[Duration] {
let linger = libc.Linger(l_onoff: 0 as Int32, l_linger: 0 as Int32)
let size = 8 as Int32
let res = libc.getsockopt(
@socket.inner,
libc.SOL_SOCKET as Int32,
libc.SO_LINGER as Int32,
(mut linger) as Pointer[UInt8],
mut size,
)
as Int
# Similar to get_option(), this method shouldn't ever reach this point, but
# we panic just in case we do.
if res != 0 { sys.getsockopt_error }
if linger.l_onoff as Int != 0 {
Option.Some(Duration.from_secs(linger.l_linger as Int))
} else {
Option.None
}
}fn pub linger -> Option[Duration]Returns the value of the SO_LINGER option.
linger=
Show source codeHide source code
fn pub mut linger=(value: Option[Duration]) -> Result[Nil, Error] {
let linger = libc.Linger(l_onoff: 0 as Int32, l_linger: 0 as Int32)
match value {
case Some(d) -> {
linger.l_onoff = 1 as Int32
linger.l_linger = d.to_secs.to_int as Int32
}
case _ -> {}
}
let res = libc.setsockopt(
@socket.inner,
libc.SOL_SOCKET as Int32,
libc.SO_LINGER as Int32,
(mut linger) as Pointer[UInt8],
8 as Int32,
)
as Int
if res == 0 { Result.Ok(nil) } else { Result.Error(Error.last_os_error) }
}fn pub mut linger=(value: Option[Duration]) -> Result[Nil, Error]Sets the value of the SO_LINGER option.
If a Some is given, the linger value is set to the duration in seconds. If
a None is given, the linger value is instead reset.
On most platforms the linger duration has a precision of whole seconds. If a
Duration is supplied that is less than one second long or contains
fractional seconds, the value may be truncated or rounded to the nearest
second.
listen
Show source codeHide source code
fn pub mut listen -> Result[Nil, Error] {
sys.listen(@socket.inner, MAXIMUM_LISTEN_BACKLOG)
}fn pub mut listen -> Result[Nil, Error]Marks this socket as being ready to accept incoming connections using
accept().
Examples
Marking a socket as a listener:
import std.net.socket (Socket)
import std.net.ip (IpAddress)
let socket = Socket.stream(ipv6: false).get
socket.bind(ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
socket.listen.get
local_address
Show source codeHide source code
fn pub local_address -> Result[SocketAddress, Error] {
match sys.ip_local_address(@socket) {
case Ok((ip, port)) -> Result.Ok(SocketAddress(ip, port))
case Error(e) -> Result.Error(e)
}
}fn pub local_address -> Result[SocketAddress, Error]Returns the local address of this socket.
no_delay=
Show source codeHide source code
fn pub mut no_delay=(value: Bool) -> Result[Nil, Error] {
set_option(libc.IPPROTO_TCP, libc.TCP_NODELAY, value.to_int)
}fn pub mut no_delay=(value: Bool) -> Result[Nil, Error]Sets the value of the TCP_NODELAY option.
no_delay?
Show source codeHide source code
fn pub no_delay? -> Bool {
get_option(libc.IPPROTO_TCP, libc.TCP_NODELAY) != 0
}fn pub no_delay? -> BoolReturns true if the TCP_NODELAY option is set.
only_ipv6=
Show source codeHide source code
fn pub mut only_ipv6=(value: Bool) -> Result[Nil, Error] {
set_option(libc.IPPROTO_IPV6, libc.IPV6_V6ONLY, value.to_int)
}fn pub mut only_ipv6=(value: Bool) -> Result[Nil, Error]Sets the value of the IPV6_V6ONLY option.
peer_address
Show source codeHide source code
fn pub peer_address -> Result[SocketAddress, Error] {
match sys.ip_peer_address(@socket) {
case Ok((ip, port)) -> Result.Ok(SocketAddress(ip, port))
case Error(e) -> Result.Error(e)
}
}fn pub peer_address -> Result[SocketAddress, Error]Returns the peer address of this socket.
Show source codeHide source code
fn pub mut print[B: Bytes](bytes: ref B) -> Result[Nil, E] {
try write(bytes)
write('\n')
}fn pub mut print[B: Bytes](bytes: ref B) -> Result[Nil, E]Writes the entirety of bytes to the underlying stream, followed by
a Unix newline.
read
Show source codeHide source code
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Error] {
sys.read(@socket, into, size, @deadline)
}fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Error]Reads up to size bytes from self into the given ByteArray, returning
the number of bytes read.
The into argument is the ByteArray to read the bytes into. The capacity
of this ByteArray is increased automatically if necessary.
The size argument specifies how many bytes are to be read.
The return value is the number of bytes read.
The number of bytes read may be less than size. This can happen for
different reasons, such as when all input is consumed or not enough data is
available (yet).
read_all
Show source codeHide source code
fn pub mut read_all(bytes: mut ByteArray) -> Result[Int, E] {
let mut total = 0
let mut read_size = INITIAL_READ_ALL_SIZE
loop {
match read(into: bytes, size: read_size) {
case Ok(0) -> return Result.Ok(total)
case Ok(n) -> {
total += n
# To reduce the number of calls to `Reader.read` when there's lots of
# input to consume, we increase the read size if deemed beneficial.
if read_size < MAX_READ_ALL_SIZE and n == read_size { read_size *= 2 }
}
case Error(e) -> throw e
}
}
}fn pub mut read_all(bytes: mut ByteArray) -> Result[Int, E]Reads from self into the given ByteArray, returning when all input is
consumed.
The return value is the number of bytes read.
Errors
This method returns an Error if the underlying call to Read.read returns
an Error.
read_exact
Show source codeHide source code
fn pub mut read_exact(
into: mut ByteArray,
size: Int,
) -> Result[Nil, ReadExactError[E]] {
let mut pending = size
while pending > 0 {
match read(into, pending) {
case Ok(0) if pending > 0 -> throw ReadExactError.EndOfInput
case Ok(n) -> pending -= n
case Error(e) -> throw ReadExactError.Read(e)
}
}
Result.Ok(nil)
}fn pub mut read_exact(into: mut ByteArray, size: Int) -> Result[Nil, ReadExactError[E]]Reads exactly size bytes into into.
Whereas Read.read might return early if fewer bytes are available in the
input stream, Read.read_exact continues reading until the desired amount
of bytes is read.
Errors
If the end of the input stream is encountered before filling the buffer, an
Error.EndOfInput error is returned.
If an error is returned, no assumption can be made about the state of the
into buffer, i.e. there's no guarantee data read so far is in the buffer
in the event of an error.
receive_buffer_size=
Show source codeHide source code
fn pub mut receive_buffer_size=(value: Int) -> Result[Nil, Error] {
set_option(libc.SOL_SOCKET, libc.SO_RCVBUF, value.to_int)
}fn pub mut receive_buffer_size=(value: Int) -> Result[Nil, Error]Sets the value of the SO_RCVBUF option.
receive_from
Show source codeHide source code
fn pub mut receive_from(
bytes: mut ByteArray,
size: Int,
) -> Result[(Int, SocketAddress), Error] {
match sys.receive_from_ip(@socket, bytes, size, @deadline) {
case Ok((read, ip, port)) -> Result.Ok((read, SocketAddress(ip, port)))
case Error(e) -> Result.Error(e)
}
}fn pub mut receive_from(bytes: mut ByteArray, size: Int) -> Result[(Int, SocketAddress), Error]Receives a single datagram message on the socket, returning the size of the message and the address the message was sent from.
The message is read into the given ByteArray, and up to size bytes will
be read.
Examples
Sending a message to ourselves and receiving it:
import std.net.socket (Socket)
import std.net.ip (IpAddress)
let socket = Socket.datagram(ipv6: false).get
let bytes = ByteArray.new
socket.send_to('hello', ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
let received_from = socket.receive_from(bytes: bytes, size: 5).get
bytes.to_string # => 'hello'
received_from.0 # => 5
received_from.1.address # => '0.0.0.0'
received_from.1.port # => 9999
reset_deadline
Show source codeHide source code
fn pub mut reset_deadline {
@deadline = net.NO_DEADLINE
}fn pub mut reset_deadlineResets the deadline.
Examples
import std.net.socket (Socket)
import std.time (Duration)
let socket = Socket.datagram(ipv6: false)
socket.timeout_after = Duration.from_secs(5)
socket.reset_deadline
reuse_address=
Show source codeHide source code
fn pub mut reuse_address=(value: Bool) -> Result[Nil, Error] {
set_option(libc.SOL_SOCKET, libc.SO_REUSEADDR, value.to_int)
}fn pub mut reuse_address=(value: Bool) -> Result[Nil, Error]Sets the value of the SO_REUSEADDR option.
reuse_port=
Show source codeHide source code
fn pub mut reuse_port=(value: Bool) -> Result[Nil, Error] {
set_option(libc.SOL_SOCKET, libc.SO_REUSEPORT, value.to_int)
}fn pub mut reuse_port=(value: Bool) -> Result[Nil, Error]Sets the value of the SO_REUSEPORT option.
Not all platforms may support this option, in which case the supplied argument will be ignored.
send_buffer_size=
Show source codeHide source code
fn pub mut send_buffer_size=(value: Int) -> Result[Nil, Error] {
set_option(libc.SOL_SOCKET, libc.SO_SNDBUF, value.to_int)
}fn pub mut send_buffer_size=(value: Int) -> Result[Nil, Error]Sets the value of the SO_SNDBUF option.
send_file
Show source codeHide source code
fn pub mut send_file(file: mut ReadOnlyFile) -> Result[Int, Error] {
sys.send_file_stream(file, self)
}fn pub mut send_file(file: mut ReadOnlyFile) -> Result[Int, Error]Sends a read-only file to the other half of self, without the need for an
intermediate buffer.
Upon success the number of copied bytes is returned.
Upon returning from this method, the cursor/offset of the source file is the same as it was before calling this method.
Platform differences
The exact mechanism used for sending the file may vary per platform. For
example, on FreeBSD, Linux and macOS this method uses the sendfile system
call.
Fallbacks
Not all platforms or socket types support zero-copy sending of files. In such cases a userspace copy is performed. Such a fallback is applied to:
- TLS sockets provided by
std.net.tls UdpSocket.send_fileandUnixDatagram.send_fileon FreeBSD and macOS
The userspace implementation copies data in chunks of 32 KiB and resets the
cursor of file to its original position after copying the data. While
resetting the cursor incurs a small cost, it ensures behavior is consistent
with the kernel implementations of this method.
Examples
import std.fs.file (ReadOnlyFile)
import std.net.ip (IpAddress)
import std.net.socket (UdpSocket)
let file = ReadOnlyFile.new('README.md'.to_path).or_panic
let server = UdpSocket.new(IpAddress.v4(0, 0, 0, 0), port: 9999).or_panic
let client = UdpSocket.new(IpAddress.v4(0, 0, 0, 0), port: 0).or_panic
client.connect(IpAddress.v4(0, 0, 0, 0), port: 9999).or_panic
client.send_file(file).or_panic
let buf = ByteArray.new
server.read(buf, 1024).or_panic
buf.to_string # => '...'
send_to
Show source codeHide source code
fn pub mut send_to[B: Bytes](
bytes: ref B,
ip: IpAddress,
port: Int,
) -> Result[Int, Error] {
sys.send_to_ip(@socket, bytes.pointer, bytes.size, ip, port, @deadline)
}fn pub mut send_to[B: Bytes](bytes: ref B, ip: IpAddress, port: Int) -> Result[Int, Error]Sends a Bytes value to the given address.
The return value is the number of bytes sent.
Examples
import std.net.socket (Socket)
import std.net.ip (IpAddress)
let socket = Socket.datagram(ipv6: false).get
socket.bind(ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
socket.send_to('hello', ip: IpAddress.v4(0, 0, 0, 0), port: 9999).get
shutdown
Show source codeHide source code
fn pub mut shutdown -> Result[Nil, Error] {
sys.shutdown(@socket, read: true, write: true)
}fn pub mut shutdown -> Result[Nil, Error]Shuts down both the reading and writing half of this socket.
shutdown_read
Show source codeHide source code
fn pub mut shutdown_read -> Result[Nil, Error] {
sys.shutdown(@socket, read: true, write: false)
}fn pub mut shutdown_read -> Result[Nil, Error]Shuts down the reading half of this socket.
shutdown_write
Show source codeHide source code
fn pub mut shutdown_write -> Result[Nil, Error] {
sys.shutdown(@socket, read: false, write: true)
}fn pub mut shutdown_write -> Result[Nil, Error]Shuts down the writing half of this socket.
timeout_after=
Show source codeHide source code
fn pub mut timeout_after=[T: ToInstant](deadline: ref T) {
@deadline = deadline.to_instant.to_int
}fn pub mut timeout_after=[T: ToInstant](deadline: ref T)Sets the point in time after which socket operations must time out, known as a "deadline".
Examples
Using a Duration results in this method calculating the absolute time
after which operations time out:
import std.net.socket (Socket)
import std.time (Duration)
let socket = Socket.datagram(ipv6: false)
socket.timeout_after = Duration.from_secs(5)
We can also use an Instant:
import std.net.socket (Socket)
import std.time (Duration, Instant)
let socket = Socket.datagram(ipv6: false)
socket.timeout_after = Instant.new + Duration.from_secs(5)
try_clone
Show source codeHide source code
fn pub try_clone -> Result[Socket, Error] {
let sock = net.raw_socket
try sys.try_clone(@socket, mut sock)
Result.Ok(Socket(socket: sock, deadline: net.NO_DEADLINE))
}fn pub try_clone -> Result[Socket, Error]Attempts to clone the socket.
Cloning a socket may fail, such as when the program has too many open file descriptors.
ttl=
Show source codeHide source code
fn pub mut ttl=(value: Int) -> Result[Nil, Error] {
set_option(libc.IPPROTO_IP, libc.IP_TTL, value)
}fn pub mut ttl=(value: Int) -> Result[Nil, Error]Sets the value of the IP_TTL option.
write
Show source codeHide source code
fn pub mut write[B: Bytes](bytes: ref B) -> Result[Nil, Error] {
write_all_internal(bytes.pointer, bytes.size)
}fn pub mut write[B: Bytes](bytes: ref B) -> Result[Nil, Error]Writes the entirety of bytes to the underlying stream.
Types implementing this method must guarantee that upon returning from this
method, either all of the data is written and a Ok(Nil) is returned, or
an Error is returned.
Implemented traits
Drop
impl Drop for SocketRead
impl Read[Error] for SocketWrite
impl Write[Error] for Socket