Sockets - leftmike/foment GitHub Wiki
The socket support in Foment is based on SRFI 106: Basic socket interface with one important difference: sockets are ports.
(import (foment base)) to use these procedures.
procedure: (socket? obj)
Return #t if obj is a socket and #f otherwise.
procedure: (make-socket address-family socket-domain ip-protocol)
Return a new socket. To use this socket to listen for incoming connection requests,
bind-socket, listen-socket, and accept-socket must be used. To connect this socket with a
server, connect-socket must be used. address-family, socket-domain,
and ip-protocol are specified below.
procedure: (bind-socket socket node service address-family socket-domain ip-protocol)
Bind socket to node and service. node must be a
string. If node is the empty string, then the socket will be bound to all
available IP addresses. If node is "localhost", then the socket will be
bound to all available loopback addresses. service must be a string. It may be a
numeric port number, for example, "80". Or it may be the name of a service, for example,
"http". address-family, socket-domain, and ip-protocol are
specified below.
procedure: (listen-socket socket)
procedure: (listen-socket socket backlog)
Start socket listening for incoming connections. socket must be bound
using bind-socket before calling listen-socket.
procedure: (accept-socket socket)
Wait for a client to connect to the socket. A new socket will be returned which can
be used to communicate with the connected client socket. socket may continue to be
used with accept-socket to wait for more clients to connect. socket must be put
into a listening state using listen-socket before calling accept-socket.
procedure: (connect-socket socket node service address-family socket-domain address-info ip-protocol)
Connect socket to a server. node and service must be strings. address-family, socket-domain, address-info, and ip-protocol are specified below.
procedure: (shutdown-socket socket how)
Shutdown the socket. how must be one of *shut-rd*, *shut-wr*, or *shut-rdwr*.
procedure: (send-socket socket bytevector flags)
Send the contents of bytevector on socket. flags must be 0
or *msg-oob*.
procedure: (recv-socket socket size flags)
Wait for and receive a block of data of size bytes from socket. The data
will be returned as a bytevector. A zero length bytevector indicates that the peer connection
is closed. flags must be 0, *msg-peek*, *msg-oob*, or *msg-waitall*.
procedure: (get-ip-addresses address-family)
Return a list of the local IP addresses in the specified address-family.
These are the same as SRFI 106: Basic socket interface.
This is a simple example of using sockets. The client reads a line of text, converts it to UTF-8, and sends it to the server. The server receives UTF-8, converts it to a string, and writes it.
(import (foment base))
(define (server)
(define (loop s)
;; (let ((bv (recv-socket s 128 0)))
;; (if (> (bytevector-length bv) 0)
(let ((bv (read-bytevector 128 s)))
(if (not (eof-object? bv))
(begin
(display (utf8->string bv))
(newline)
(loop s)))))
(let ((s (make-socket (address-family inet) (socket-domain stream) (ip-protocol tcp))))
(bind-socket s "localhost" "12345" (address-family inet) (socket-domain stream)
(ip-protocol tcp))
(listen-socket s)
(loop (accept-socket s))))
(define (client)
(define (loop s)
;; (socket-send s (string->utf8 (read-line)) 0)
(write-bytevector (string->utf8 (read-line)) s)
(loop s))
(let ((s (make-socket (address-family inet) (socket-domain stream) (ip-protocol tcp))))
(connect-socket s "localhost" "12345" (address-family inet) (socket-domain stream)
0 (ip-protocol tcp))
(loop s)))
(cond
((member "client" (command-line)) (client))
((member "server" (command-line)) (server))
(else (display "error: expected client or server on the command line") (newline)))