-
Notifications
You must be signed in to change notification settings - Fork 4
Sockets
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)))