AtlatestRepositorysigil-socket
sigil-socket / tree / docssocket.md
1
# Socket3
> TCP, UDP, and Unix domain socket operations for network programming.5
```scheme6
(import (sigil socket))7
```9
## TCP Client11
```scheme12
;; Connect to a TCP server (returns socket or #f)13
(define sock (tcp-connect "example.com" 80))15
;; Send an HTTP request16
(socket-write-line sock "GET / HTTP/1.0")17
(socket-write-line sock "")19
;; Read the full response20
(display (socket-read-all sock))21
(socket-close sock)22
```24
`call-with-tcp-connection` ensures the socket is closed when the procedure returns:26
```scheme27
(call-with-tcp-connection "example.com" 8028
(lambda (sock)29
(socket-write-line sock "GET / HTTP/1.0")30
(socket-write-line sock "")31
(socket-read-all sock)))32
```34
## TCP Server36
```scheme37
;; Listen on a port (0 = OS-assigned)38
(define server (tcp-listen 8080))40
;; Accept loop41
(let loop ()42
(let ((client (tcp-accept server)))43
(socket-write-line client "Hello!")44
(socket-close client)45
(loop)))46
```48
`tcp-listen` accepts an optional backlog argument (default 5). Pass port `0` for an OS-assigned port, then inspect it with `socket-local-address`.50
`call-with-tcp-server` wraps the listen/close lifecycle:52
```scheme53
(call-with-tcp-server 054
(lambda (server)55
(let ((client (tcp-accept server)))56
(socket-write-line client "Welcome")57
(socket-close client))))58
```60
## Unix Domain Sockets62
Connect to a Unix domain socket path. Not available on Windows.64
```scheme65
(define sock (unix-connect "/var/run/app.sock"))66
(socket-write-line sock "STATUS")67
(display (socket-read-line sock))68
(socket-close sock)69
```71
## Reading and Writing73
### socket-read75
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.77
```scheme78
(socket-read sock) ; read up to 4096 bytes79
(socket-read sock 1024) ; read up to 1024 bytes80
```82
### socket-read-line84
Read a single line (up to the next newline character).86
```scheme87
(socket-read-line sock) ; => "HTTP/1.0 200 OK"88
```90
### socket-write92
Write a string or bytevector. Returns the number of bytes written, or `#f` on error.94
```scheme95
(socket-write sock "Hello") ; => 596
(socket-write sock #u8(1 2 3)) ; => 397
```99
### socket-write-line101
Write a string followed by CRLF (`\r\n`).103
```scheme104
(socket-write-line sock "GET / HTTP/1.0")105
```107
### socket-read-all109
Read all data until EOF, returning the accumulated string.111
```scheme112
(define response (socket-read-all sock))113
```115
### socket-send-all117
Send all data, retrying on partial writes. Returns `#t` on success.119
```scheme120
(socket-send-all sock large-string) ; => #t121
```123
### make-line-reader125
Create a buffered line reader that handles fragmented input and CRLF line endings. Returns a procedure that yields one complete line per call.127
```scheme128
(define reader (make-line-reader sock))129
(reader) ; => "first line"130
(reader) ; => "second line"131
(reader) ; => eof-object (connection closed)132
```134
## UDP136
```scheme137
;; Create and bind a UDP socket138
(define sock (udp-socket))139
(udp-bind sock 5000)141
;; Send a datagram (sock data host port)142
(udp-send sock "ping" "127.0.0.1" 5000)144
;; Receive a datagram — returns (data host port)145
(let ((result (udp-receive sock)))146
(display (car result))) ; => "ping"148
(socket-close sock)149
```151
`udp-bind` accepts an optional host argument: `(udp-bind sock port host)`.153
`udp-receive` accepts an optional max-bytes argument (default 65535).155
## Non-blocking I/O157
```scheme158
;; Enable non-blocking mode159
(socket-set-non-blocking! sock #t)160
(socket-non-blocking? sock) ; => #t162
;; Check if data is available without blocking163
(socket-ready? sock) ; => #t or #f164
```166
### socket-select168
Wait for activity on multiple sockets. Returns `(readable writable)` — two lists of ready sockets.170
```scheme171
(let* ((result (socket-select (list sock1 sock2) '() 1000))172
(readable (car result))173
(writable (cadr result)))174
(for-each handle-data readable))175
```177
The third argument is a timeout in milliseconds.179
## Socket Info181
```scheme182
;; Type predicate183
(socket? sock) ; => #t184
(socket-closed? sock) ; => #f186
;; Local address — returns (host port)187
(socket-local-address sock) ; => ("0.0.0.0" 8080)189
;; Remote address — returns (host port)190
(socket-remote-address sock) ; => ("127.0.0.1" 54321)192
;; DNS resolution — returns list of IP strings193
(resolve-hostname "example.com") ; => ("93.184.216.34" ...)195
;; Local machine hostname196
(gethostname) ; => "my-computer"197
```199
## Options201
Disable Nagle's algorithm for lower latency on interactive protocols:203
```scheme204
(socket-set-tcp-nodelay! sock #t)205
```207
## Common Patterns209
### TCP Echo Server211
```scheme212
(import (sigil socket))214
(define (echo-server port)215
(call-with-tcp-server port216
(lambda (server)217
(let loop ()218
(let* ((client (tcp-accept server))219
(reader (make-line-reader client)))220
(let read-loop ()221
(let ((line (reader)))222
(cond223
((eof-object? line) (socket-close client))224
(else (socket-write-line client line)225
(read-loop)))))226
(loop))))))227
```229
### Line-based Protocol Client231
```scheme232
(import (sigil socket))234
(call-with-tcp-connection "localhost" 6379235
(lambda (sock)236
(socket-write-line sock "PING")237
(let ((reader (make-line-reader sock)))238
(display (reader))))) ; => "+PONG"239
```241
### UDP Messaging243
```scheme244
(import (sigil socket))246
;; Sender247
(let ((sock (udp-socket)))248
(udp-send sock "hello" "127.0.0.1" 9000)249
(socket-close sock))251
;; Receiver252
(let ((sock (udp-socket)))253
(udp-bind sock 9000)254
(let ((msg (udp-receive sock)))255
(display (car msg)) ; data256
(display (cadr msg)) ; sender host257
(display (caddr msg))) ; sender port258
(socket-close sock))259
```