NAME
Sidef::Types::Glob::SocketHandle - An open socket connection, for network communication
DESCRIPTION
This class represents an open socket connection in Sidef, wrapping a raw Perl filehandle together with a reference to the Sidef::Types::Glob::Socket that created it. SocketHandle objects are the ones you actually call bind, listen, accept, connect, send, and recv on — not the Socket object itself.
You don't normally construct a SocketHandle directly. Instead, you get one from:
Socket.new.open(domain, type, protocol)— creates a new socketSocket.new.socketpair(...)— creates a connected pair of socketsan existing SocketHandle's own "accept" — accepts an incoming connection
SYNOPSIS
# Create a TCP server
var server = Socket.new.open(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.open(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.
CONSTRUCTION
new
SocketHandle.new(sh, socket)
Low-level constructor wrapping an already-open raw filehandle (sh, as produced by Perl's socket/accept) together with a reference to the Socket object that created it. This is used internally by Socket's own open and socketpair, and by SocketHandle's own "accept" — you will not normally call it directly; use Socket.new.open(domain, type, protocol) instead.
Aliases: call
CONNECTION SETUP
bind
self.bind(address)
Binds the socket to a local address and port. This is typically used by server sockets before calling "listen". Returns a boolean.
var sock = Socket.new.open(Socket.PF_INET, Socket.SOCK_STREAM, 0)
var addr = Socket.pack_sockaddr_in(8080, Socket.INADDR_ANY)
sock.bind(addr) || die "Cannot bind: #{$!}"
listen
self.listen(queuesize)
Marks the socket as a passive socket that will accept incoming connections. Must be called after "bind" and before "accept". queuesize is the maximum length of the queue of pending connections (typically 5-128). Returns a boolean.
sock.bind(addr)
sock.listen(5) || die "Cannot listen: #{$!}"
accept
self.accept
Accepts an incoming connection on a listening socket, blocking until a client connects. Returns a new SocketHandle representing the client connection, or nil on failure.
var server = Socket.new.open(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 info = Socket.unpack_sockaddr_in(client.getpeername)
say "Connection from #{Socket.inet_ntoa(info[1])}:#{info[0]}"
client.say("Welcome!")
client.close
}
connect
self.connect(address)
Initiates a connection to a remote socket. This is typically used by client sockets. Returns a boolean.
var sock = Socket.new.open(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: #{$!}"
SENDING AND RECEIVING DATA
send
self.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 address (a packed sockaddr structure). Returns a boolean.
# TCP socket
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
self.recv(length, flags=0)
Receives up to length bytes of data from the socket. Returns the received data as a String, or nil on error.
var data = sock.recv(1024)
if (defined(data)) {
say "Received: #{data}"
}
CONNECTION INFORMATION
getsockname
self.getsockname
Returns the local address to which the socket is bound, as a packed sockaddr structure.
var addr = sock.getsockname
var info = Socket.unpack_sockaddr_in(addr)
say "Local address: #{Socket.inet_ntoa(info[1])}:#{info[0]}"
getpeername
self.getpeername
Returns the address of the peer (remote end) connected to this socket, as a packed sockaddr structure, or nil on failure.
var addr = sock.getpeername
if (defined(addr)) {
var info = Socket.unpack_sockaddr_in(addr)
say "Peer address: #{Socket.inet_ntoa(info[1])}:#{info[0]}"
}
getsockopt
self.getsockopt(level, optname)
Gets a socket option value, as a raw packed String — decode it according to the specific option (e.g. as an integer with unpack). Returns nil on failure.
var level = Socket.SOL_SOCKET
var raw = sock.getsockopt(level, Socket.SO_REUSEADDR)
setsockopt
self.setsockopt(level, optname, optval)
Sets a socket option value. Returns a boolean.
# 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)
CLOSING A CONNECTION
shutdown
self.shutdown(how)
Shuts down part or all of the socket connection, without necessarily closing the underlying filehandle (see "close" in Sidef::Types::Glob::FileHandle for that). how is one of:
0 (
Socket.SHUT_RD) - Further receives are disallowed1 (
Socket.SHUT_WR) - Further sends are disallowed2 (
Socket.SHUT_RDWR) - Further sends and receives are disallowed
Returns a boolean.
# Finish sending data and close the write side
sock.shutdown(Socket.SHUT_WR)
# Read remaining data from the peer
var remaining = sock.slurp
# Close completely
sock.close
EXAMPLES
TCP Server
var server = Socket.new.open(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"
client.say("Welcome to the server!")
var request = client.readline
say "Received: #{request}"
client.close
}
TCP Client
var sock = Socket.new.open(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.open(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 info = Socket.unpack_sockaddr_in(peer)
say "Received from #{Socket.inet_ntoa(info[1])}:#{info[0]}: #{data}"
}
UDP Client
var sock = Socket.new.open(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
Sidef::Types::Glob::Socket - Creates SocketHandle objects and provides constants/conversion helpers
Sidef::Types::Glob::FileHandle - Parent class with I/O methods
Socket - Perl's Socket module documentation for constants and helper functions