This example creates a TCP server and client on the IPv4 loopback interface. The server listens on an automatically assigned port, accepts the client, and echoes one message.

library(socketR)

local({
  server <- socket_create("inet", "stream")
  client <- socket_create("inet", "stream")
  peer <- NULL

  on.exit({
    if (!is.null(peer) && socket_is_open(peer)) socket_close(peer)
    if (socket_is_open(client)) socket_close(client)
    if (socket_is_open(server)) socket_close(server)
  }, add = TRUE)

  socket_reuse_address(server, TRUE)
  socket_bind(server, "127.0.0.1", 0L)
  port <- socket_local_name(server)$port
  socket_listen(server)

  socket_connect(client, "127.0.0.1", port)
  peer <- socket_accept(server)

  socket_send(client, "hello from R")
  socket_poll(peer, "read", timeout_ms = 1000L)
  message <- rawToChar(socket_receive(peer, n = 12L))
  message
})

The same handle API also supports IPv6, UDP datagrams, nonblocking mode, readiness polling, shutdown, and generic typed socket options. See the function reference for those lower-level operations and the Socket R6 class for method-style usage.

Automatic IPv4/IPv6 selection

The socket_listen_auto() and socket_connect_auto() helpers resolve and try IPv6 and IPv4 endpoints in preference order. This avoids hard-coding an address family when both may be available.

library(socketR)

server <- socket_listen_auto(port = 0L)
client <- socket_connect_auto(server$address, server$port)
peer <- socket_accept(server)

socket_send(client, "hello from auto-connect")
socket_poll(peer, "read", timeout_ms = 1000L)
rawToChar(socket_receive(peer, n = 23L))

socket_close(peer)
socket_close(client)
socket_close(server)

The default preference is IPv6 followed by IPv4. Use prefer = "inet" or prefer = "inet6" when an application requires a specific address family.

Unix-domain sockets

Unix-domain sockets communicate between processes on the same host using a filesystem path instead of an IP address and port.

library(socketR)

path <- tempfile("socketr-")
server <- socket_create("unix", "stream")
client <- socket_create("unix", "stream")
peer <- NULL

on.exit({
  if (!is.null(peer) && socket_is_open(peer)) socket_close(peer)
  if (socket_is_open(client)) socket_close(client)
  if (socket_is_open(server)) socket_close(server)
  if (file.exists(path)) unlink(path)
}, add = TRUE)

socket_bind(server, path)
socket_listen(server)
socket_connect(client, path)
peer <- socket_accept(server)

socket_send(client, "hello over Unix")
socket_poll(peer, "read", timeout_ms = 1000L)
rawToChar(socket_receive(peer, n = 15L))

The path must be removed after use before another server binds to the same Unix-domain socket address.