Socket
TCP, UDP, and Unix domain socket operations for network programming.
(import (sigil socket))TCP Client
;; Connect to a TCP server (returns socket or #f)
(define sock (tcp-connect "example.com" 80))
;; Send an HTTP request
(socket-write-line sock "GET / HTTP/1.0")
(socket-write-line sock "")
;; Read the full response
(display (socket-read-all sock))
(socket-close sock)call-with-tcp-connection ensures the socket is closed when the procedure returns:
(call-with-tcp-connection "example.com" 80
(lambda (sock)
(socket-write-line sock "GET / HTTP/1.0")
(socket-write-line sock "")
(socket-read-all sock)))TCP Server
;; Listen on a port (0 = OS-assigned)
(define server (tcp-listen 8080))
;; Accept loop
(let loop ()
(let ((client (tcp-accept server)))
(socket-write-line client "Hello!")
(socket-close client)
(loop)))tcp-listen accepts an optional backlog argument (default 5). Pass port 0 for an OS-assigned port, then inspect it with socket-local-address.
call-with-tcp-server wraps the listen/close lifecycle:
(call-with-tcp-server 0
(lambda (server)
(let ((client (tcp-accept server)))
(socket-write-line client "Welcome")
(socket-close client))))Unix Domain Sockets
Connect to a Unix domain socket path. Not available on Windows.
(define sock (unix-connect "/var/run/app.sock"))
(socket-write-line sock "STATUS")
(display (socket-read-line sock))
(socket-close sock)Reading and Writing
socket-read
Read up to max-bytes (default 4096) from a socket. Returns a string, empty string if no data is available in non-blocking mode, or eof-object when the connection is closed.
(socket-read sock) ; read up to 4096 bytes
(socket-read sock 1024) ; read up to 1024 bytessocket-read-line
Read a single line (up to the next newline character).
(socket-read-line sock) ; => "HTTP/1.0 200 OK"socket-write
Write a string or bytevector. Returns the number of bytes written, or #f on error.
(socket-write sock "Hello") ; => 5
(socket-write sock #u8(1 2 3)) ; => 3socket-write-line
Write a string followed by CRLF (\r\n).
(socket-write-line sock "GET / HTTP/1.0")socket-read-all
Read all data until EOF, returning the accumulated string.
(define response (socket-read-all sock))socket-send-all
Send all data, retrying on partial writes. Returns #t on success.
(socket-send-all sock large-string) ; => #tmake-line-reader
Create a buffered line reader that handles fragmented input and CRLF line endings. Returns a procedure that yields one complete line per call.
(define reader (make-line-reader sock))
(reader) ; => "first line"
(reader) ; => "second line"
(reader) ; => eof-object (connection closed)UDP
;; Create and bind a UDP socket
(define sock (udp-socket))
(udp-bind sock 5000)
;; Send a datagram (sock data host port)
(udp-send sock "ping" "127.0.0.1" 5000)
;; Receive a datagram — returns (data host port)
(let ((result (udp-receive sock)))
(display (car result))) ; => "ping"
(socket-close sock)udp-bind accepts an optional host argument: (udp-bind sock port host).
udp-receive accepts an optional max-bytes argument (default 65535).
Non-blocking I/O
;; Enable non-blocking mode
(socket-set-non-blocking! sock #t)
(socket-non-blocking? sock) ; => #t
;; Check if data is available without blocking
(socket-ready? sock) ; => #t or #fsocket-select
Wait for activity on multiple sockets. Returns (readable writable) — two lists of ready sockets.
(let* ((result (socket-select (list sock1 sock2) '() 1000))
(readable (car result))
(writable (cadr result)))
(for-each handle-data readable))The third argument is a timeout in milliseconds.
Socket Info
;; Type predicate
(socket? sock) ; => #t
(socket-closed? sock) ; => #f
;; Local address — returns (host port)
(socket-local-address sock) ; => ("0.0.0.0" 8080)
;; Remote address — returns (host port)
(socket-remote-address sock) ; => ("127.0.0.1" 54321)
;; DNS resolution — returns list of IP strings
(resolve-hostname "example.com") ; => ("93.184.216.34" ...)
;; Local machine hostname
(gethostname) ; => "my-computer"Options
Disable Nagle's algorithm for lower latency on interactive protocols:
(socket-set-tcp-nodelay! sock #t)Common Patterns
TCP Echo Server
(import (sigil socket))
(define (echo-server port)
(call-with-tcp-server port
(lambda (server)
(let loop ()
(let* ((client (tcp-accept server))
(reader (make-line-reader client)))
(let read-loop ()
(let ((line (reader)))
(cond
((eof-object? line) (socket-close client))
(else (socket-write-line client line)
(read-loop)))))
(loop))))))Line-based Protocol Client
(import (sigil socket))
(call-with-tcp-connection "localhost" 6379
(lambda (sock)
(socket-write-line sock "PING")
(let ((reader (make-line-reader sock)))
(display (reader))))) ; => "+PONG"UDP Messaging
(import (sigil socket))
;; Sender
(let ((sock (udp-socket)))
(udp-send sock "hello" "127.0.0.1" 9000)
(socket-close sock))
;; Receiver
(let ((sock (udp-socket)))
(udp-bind sock 9000)
(let ((msg (udp-receive sock)))
(display (car msg)) ; data
(display (cadr msg)) ; sender host
(display (caddr msg))) ; sender port
(socket-close sock))