NAME

Sidef::Types::Glob::SocketHandle - Socket handle interface for network programming

DESCRIPTION

This class implements a socket handle interface for network communication in Sidef. It provides methods for creating and managing network sockets, supporting both client and server operations over TCP/IP and other protocols. SocketHandle wraps Perl's socket functionality and provides a Sidef-friendly API for network programming.

SYNOPSIS

# Create a server socket
var server = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, Socket.IPPROTO_TCP)
server.bind(Socket.pack_sockaddr_in(8080, Socket.INADDR_ANY))
server.listen(5)

say "Server listening on port 8080..."
var client = server.accept

# Read from client
var data = client.readline
say "Received: #{data}"

# Send response
client.say("Hello from server!")
client.close

# Create a client socket
var sock = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, Socket.IPPROTO_TCP)
var addr = Socket.pack_sockaddr_in(80, Socket.inet_aton("example.com"))
sock.connect(addr)
sock.say("GET / HTTP/1.0\r\n\r\n")
say sock.slurp
sock.close

INHERITS

Inherits methods from:

* Sidef::Types::Glob::FileHandle

This means all file handle methods (like read, write, print, say, close, etc.) are available on socket handles as well.

METHODS

new

SocketHandle.new(domain, type, protocol)
Socket.new(domain, type, protocol)

Creates a new socket handle with the specified domain (address family), socket type, and protocol.

Parameters:

  • domain - Address family (e.g., Socket.PF_INET for IPv4, Socket.PF_INET6 for IPv6)

  • type - Socket type (e.g., Socket.SOCK_STREAM for TCP, Socket.SOCK_DGRAM for UDP)

  • protocol - Protocol number (e.g., Socket.IPPROTO_TCP, Socket.IPPROTO_UDP, or 0 for default)

Returns: A new SocketHandle object, or nil on failure.

Example:

var tcp_socket = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, Socket.IPPROTO_TCP)
var udp_socket = Socket.new(Socket.PF_INET, Socket.SOCK_DGRAM, Socket.IPPROTO_UDP)

Aliases: call

bind

socket.bind(address)

Binds the socket to a local address and port. This is typically used by server sockets before calling listen().

Parameters:

  • address - Packed socket address structure (created with Socket.pack_sockaddr_in or similar)

Returns: True on success, false on failure.

Example:

var sock = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, 0)
var addr = Socket.pack_sockaddr_in(8080, Socket.INADDR_ANY)
sock.bind(addr) || die "Cannot bind: #{$!}"

listen

socket.listen(queuesize)

Marks the socket as a passive socket that will accept incoming connections. Must be called after bind() and before accept().

Parameters:

  • queuesize - Maximum length of the queue of pending connections (typically 5-128)

Returns: True on success, false on failure.

Example:

sock.bind(addr)
sock.listen(5) || die "Cannot listen: #{$!}"

accept

socket.accept

Accepts an incoming connection on a listening socket. This blocks until a client connects.

Returns: A new SocketHandle object representing the client connection, or nil on failure.

Example:

var server = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, 0)
server.bind(Socket.pack_sockaddr_in(8080, Socket.INADDR_ANY))
server.listen(5)

loop {
    var client = server.accept || next
    var peer = Socket.unpack_sockaddr_in(client.getpeername)
    say "Connection from #{Socket.inet_ntoa(peer[1])}:#{peer[0]}"
    client.say("Welcome!")
    client.close
}

connect

socket.connect(address)

Initiates a connection to a remote socket. This is typically used by client sockets.

Parameters:

  • address - Packed socket address structure of the remote endpoint

Returns: True on success, false on failure.

Example:

var sock = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, 0)
var addr = Socket.pack_sockaddr_in(80, Socket.inet_aton("192.168.1.1"))
sock.connect(addr) || die "Cannot connect: #{$!}"

send

socket.send(message, flags=0, to=nil)

Sends a message through the socket. For connected sockets (TCP), the to parameter is not needed. For connectionless sockets (UDP), to specifies the destination.

Parameters:

  • message - The data to send (string or bytes)

  • flags - Optional flags for send operation (default: 0)

  • to - Optional destination address for connectionless sockets

Returns: The number of bytes sent, or nil on error.

Example:

# TCP socket
var sent = sock.send("Hello, World!")

# UDP socket with destination
var addr = Socket.pack_sockaddr_in(9999, Socket.inet_aton("192.168.1.100"))
sock.send("UDP message", 0, addr)

recv

socket.recv(length, flags=0)

Receives data from the socket.

Parameters:

  • length - Maximum number of bytes to receive

  • flags - Optional flags for receive operation (default: 0)

Returns: The received data as a string, or nil on error.

Example:

var data = sock.recv(1024)
if (defined(data)) {
    say "Received: #{data}"
}

getsockname

socket.getsockname

Returns the local address to which the socket is bound.

Returns: Packed socket address structure, or nil on failure.

Example:

var addr = sock.getsockname
if (defined(addr)) {
    var (port, ip) = Socket.unpack_sockaddr_in(addr)
    say "Local address: #{Socket.inet_ntoa(ip)}:#{port}"
}

getpeername

socket.getpeername

Returns the address of the peer (remote end) connected to this socket.

Returns: Packed socket address structure, or nil on failure.

Example:

var addr = sock.getpeername
if (defined(addr)) {
    var (port, ip) = Socket.unpack_sockaddr_in(addr)
    say "Peer address: #{Socket.inet_ntoa(ip)}:#{port}"
}

getsockopt

socket.getsockopt(level, optname)

Gets a socket option value.

Parameters:

  • level - Protocol level (e.g., Socket.SOL_SOCKET)

  • optname - Option name (e.g., Socket.SO_REUSEADDR, Socket.SO_KEEPALIVE)

Returns: The option value, or nil on failure.

Example:

var reuse = sock.getsockopt(Socket.SOL_SOCKET, Socket.SO_REUSEADDR)
say "SO_REUSEADDR is #{reuse ? 'enabled' : 'disabled'}"

setsockopt

socket.setsockopt(level, optname, optval)

Sets a socket option value.

Parameters:

  • level - Protocol level (e.g., Socket.SOL_SOCKET)

  • optname - Option name (e.g., Socket.SO_REUSEADDR, Socket.SO_KEEPALIVE)

  • optval - Option value to set

Returns: True on success, false on failure.

Example:

# Enable address reuse (useful for servers)
sock.setsockopt(Socket.SOL_SOCKET, Socket.SO_REUSEADDR, 1) || 
    die "Cannot set SO_REUSEADDR: #{$!}"

# Enable TCP keepalive
sock.setsockopt(Socket.SOL_SOCKET, Socket.SO_KEEPALIVE, 1)

shutdown

socket.shutdown(how)

Shuts down part or all of the socket connection.

Parameters:

  • how - How to shut down the socket:

    • 0 (SHUT_RD) - Further receives are disallowed

    • 1 (SHUT_WR) - Further sends are disallowed

    • 2 (SHUT_RDWR) - Further sends and receives are disallowed

Returns: True on success, false on failure.

Example:

# Finish sending data and close the write side
sock.shutdown(1)

# Read remaining data from the peer
var remaining = sock.slurp

# Close completely
sock.close

COMMON USAGE PATTERNS

TCP Server

var server = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, 0)
server.setsockopt(Socket.SOL_SOCKET, Socket.SO_REUSEADDR, 1)
server.bind(Socket.pack_sockaddr_in(8080, Socket.INADDR_ANY))
server.listen(10)

say "Server started on port 8080"

loop {
    var client = server.accept || next
    say "Client connected"
    
    # Handle client in a fork or thread
    client.say("Welcome to the server!")
    var request = client.readline
    say "Received: #{request}"
    
    client.close
}

TCP Client

var sock = Socket.new(Socket.PF_INET, Socket.SOCK_STREAM, 0)
var addr = Socket.pack_sockaddr_in(80, Socket.inet_aton("example.com"))

sock.connect(addr) || die "Cannot connect: #{$!}"

sock.say("GET / HTTP/1.1")
sock.say("Host: example.com")
sock.say("Connection: close")
sock.say("")

say sock.slurp
sock.close

UDP Server

var sock = Socket.new(Socket.PF_INET, Socket.SOCK_DGRAM, 0)
sock.bind(Socket.pack_sockaddr_in(9999, Socket.INADDR_ANY))

say "UDP server listening on port 9999"

loop {
    var data = sock.recv(1024)
    defined(data) || next
    
    var peer = sock.getpeername
    var (port, ip) = Socket.unpack_sockaddr_in(peer)
    say "Received from #{Socket.inet_ntoa(ip)}:#{port}: #{data}"
}

UDP Client

var sock = Socket.new(Socket.PF_INET, Socket.SOCK_DGRAM, 0)
var addr = Socket.pack_sockaddr_in(9999, Socket.inet_aton("192.168.1.100"))

sock.send("Hello, UDP server!", 0, addr)

var response = sock.recv(1024)
say "Response: #{response}" if defined(response)

sock.close

SEE ALSO

AUTHOR

Daniel "trizen" Șuteu

LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Sidef itself.