1 Overview
1.1 Installation
1.2 License
2 API
2.1 Sockets
2.1.1 Primitives
socket
socket?
stream-socket?
socket-close
socket-closed?
2.1.2 Address Binding
socket-bind
socket-getsockname
socket-getpeername
2.1.3 Connections
socket-listen
socket-accept
socket-accept*
socket-connect
socket-connect*
socket-shutdown
2.1.4 Binary I/ O
socket-send
socket-send*
socket-sendto
socket-sendto*
socket-recv
socket-recv*
socket-recvfrom
socket-recvfrom*
socket-send-all
socket-recv-all
socket-send/ port
socket-recv/ port
2.1.5 Port I/ O
socket-input-port
socket-output-port
open-socket-stream
2.1.6 Control I/ O
socket-sendmsg
socket-sendmsg*
socket-recvmsg
socket-recvmsg*
2.1.7 Sockopts
socket-getsockopt
socket-setsockopt
socket-getsockopt-raw
socket-setsockopt-raw
2.1.8 Synchronization
socket-recv-evt
socket-send-evt
socket-connect-evt
socket-accept-evt
2.2 Addresses
inet-address
inet4-address
inet6-address
inet-address?
inet4-address?
inet6-address?
inet-address-family
inet-address-host
inet-address-port
inet-address=?
inet-address->vector
vector->inet-address
pack-address
unpack-address
current-address-resolver
2.3 Exceptions
exn: fail: socket
exn: fail: socket: blocking?
2.4 Constants
2.4.1 Features
SOCKET_ HAVE_ RAW
SOCKET_ HAVE_ IPV6
SOCKET_ HAVE_ UNIX
2.4.2 Fixed Addresses
INADDR_ ANY
INADDR_ LOOPBACK
INADDR_ BROADCAST
IN6ADDR_ ANY
IN6ADDR_ LOOPBACK
2.4.3 Standard Constants
SHUT_ RD
SHUT_ WR
SHUT_ RDWR
AF_ UNSPEC
PF_ UNSPEC
AF_ INET
PF_ INET
AF_ INET6
PF_ INET6
AF_ UNIX
PF_ UNIX
IPPROTO_ IP
IPPROTO_ IPV6
IPPROTO_ TCP
IPPROTO_ UDP
IPPROTO_ ICMP
IPPROTO_ RAW
SOCK_ STREAM
SOCK_ DGRAM
SOCK_ RAW
SOL_ SOCKET
SO_ ACCEPTCONN
SO_ BROADCAST
SO_ DEBUG
SO_ DONTROUTE
SO_ ERROR
SO_ KEEPALIVE
SO_ OOBLINE
SO_ PASSCRED
SO_ RCVBUF
SO_ SNDBUF
SO_ RCVLOWAT
SO_ SNDLOWAT
SO_ RCVTIMEO
SO_ SNDTIMEO
SO_ REUSEADDR
SO_ REUSEPORT
SO_ TYPE
SO_ TIMESTAMP
SO_ USELOOPBACK
IP_ ADD_ MEMBERSHIP
IP_ DROP_ MEMBERSHIP
IP_ HDRINCL
IP_ MTU
IP_ MTU_ DISCOVER
IP_ MULTICAST_ IF
IP_ MULTICAST_ LOOP
IP_ MULTICAST_ TTL
IP_ OPTIONS
IP_ PKTINFO
IP_ RECVDSTADDR
IP_ RECVIF
IP_ RECVTOS
IP_ RECVTTL
IP_ TOS
IP_ TTL
IPV6_ ADD_ MEMBERSHIP
IPV6_ DROP_ MEMBERSHIP
IPV6_ MULTICAST_ HOPS
IPV6_ MULTICAST_ IF
IPV6_ MULTICAST_ LOOP
IPV6_ MTU
IPV6_ MTU_ DISCOVER
IPV6_ CHECKSUM
IPV6_ PKTINFO
IPV6_ RECVERR
IPV6_ UNICAST_ HOPS
IPV6_ RTHDR
IPV6_ AUTHHDR
IPV6_ DSTOPTS
IPV6_ HOPOPTS
IPV6_ FLOWINFO
IPV6_ HOPLIMIT
TCP_ KEEPALIVE
TCP_ KEEPIDLE
TCP_ KEEPINTVL
TCP_ MAXRT
TCP_ MAXSEG
TCP_ NODELAY
TCP_ SYNCNT
IP_ PMTUDISC_ WANT
IP_ PMTUDISC_ DONT
IP_ PMTUDISC_ DO
IPV6_ PKTOPTIONS
IPTOS_ LOWDELAY
IPTOS_ THROUGHPUT
IPTOS_ RELIABILITY
IPTOS_ MINCOST
MSG_ DONTROUTE
MSG_ DONTWAIT
MSG_ MORE
MSG_ OOB
2.4.4 Error Codes
EACCES
EAFNOSUPPORT
EPFNOSUPPORT
EPROTONOSUPPORT
ENOBUFS
EFAULT
EADDRINUSE
EINVAL
ENOTSOCK
EOPNOTSUPP
EWOULDBLOCK
ECONNABORTED
EMFILE
ETIMEDOUT
ESOCKTNOSUPPORT
EALREADY
ECONNREFUSED
EISCONN
ENETUNREACH
ECONNRESET
EDESTADDRREQ
EMSGSIZE
ENOTCONN
EPROTOTYPE
ENOPROTOOPT
EINPROGRESS
EADDRNOTAVAIL
ENETDOWN
ENETRESET
ESHUTDOWN
EHOSTDOWN
EHOSTUNREACH
ENOMEM
ENFILE
EBADF
EPIPE
3 Examples
3.1 A URL fetcher
3.2 An echo server
3.3 UDP echos
Version: 4.1.5.4

mzsocket

1 Overview

mzsocket is a native extension library for PLT-scheme, that provides the BSD/POSIX sockets interface.

It supports IPv4, IPv6, Unix domain, and raw sockets depending on availability on the host platform.

1.1 Installation

To use the library through PLaneT:

  > (require (planet vyzo/socket))

To locally install the library, extract the library archive to your collects directory and run

  setup-plt -l socket

To use the local library:

  > (require socket)

To run basic tests on the library:

  > (require (only socket/test run-tests))

  > (run-tests)

1.2 License

(C) Copyright 2007-2009 Dimitris Vyzovitis <vyzo at media dot mit dot edu>

mzsocket is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

mzsocket is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with mzsocket. If not, see <http://www.gnu.org/licenses/>.

2 API

 (require socket)
 (require (planet vyzo/socket))

The socket API closely follows the native POSIX/BSD API. In general, all operations that might block come in two variants op and op*. The blocking variant op blocks the current scheme thread until the system call completes. The non-blocking variant op* raises an exception with error code EWOULDBLOCK if the operation cannot be completed (see Exceptions). Non-blocking operations can be synchronized in a matter similar to select using events and sync (see Synchronization) .

2.1 Sockets

2.1.1 Primitives

(socket [family type proto])  socket?
  family : fixnum? = PF_INET
  type : fixnum? = SOCK_STREAM
  proto : fixnum? = 0

Socket constructor.

Creates a new socket, registered with the current custodian. Sockets are implicitly closed when they become unreachable.

(socket? o)  boolean?
  o : any

Socket predicate.

(stream-socket? o)  boolean?
  o : any

True for SOCK_STREAM sockets.

(socket-close o)  void?
  o : socket?

Explicitly close a socket.

(socket-closed? o)  boolean?
  o : socket?

True if the socket o has been closed.

2.1.2 Address Binding

(socket-bind o addr)  void?
  o : socket?
  addr : address

Explicitly bind a socket to a specific address.

(socket-getsockname o)  address
  o : socket?

The local address of a bound socket.

(socket-getpeername o)  address
  o : socket?

The remote address of a connected socket.

2.1.3 Connections

(socket-listen o backlog)  void?
  o : socket?
  backlog : fixnum?

Listens for incoming connections in a stream socket.

(socket-accept o)  
socket? address
  o : socket?
(socket-accept* o)  
socket? address
  o : socket?

Accept an incoming connection in a stream socket.

(socket-connect o peer)  void?
  o : socket?
  peer : address
(socket-connect* o peer)  boolean?
  o : socket?
  peer : address

Connect a socket to a remote endpoint.

The non-blocking variant socket-connect* returns #t if the connection can be immediately completed; otherwise, an asynchronous connection is initiated and #f is returned.

(socket-shutdown o how)  void?
  o : socket?
  how : fixnum?

Directional socket shutdown. how must be one of SHUT_RD, SHUT_WR, SHUT_RDWR.

2.1.4 Binary I/O

(socket-send o x [b e flags])  fixnum?
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0
(socket-send* o x [b e flags])  fixnum?
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0
(socket-sendto o peer x [b e flags])  fixnum?
  o : socket?
  peer : address
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0
(socket-sendto* o peer x [b e flags])  fixnum?
  o : socket?
  peer : address
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0

Send the bytes contained in x[b e). Return the number of bytes written.

(socket-recv o x [b e flags])  fixnum?
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0
(socket-recv* o x [b e flags])  fixnum?
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0
(socket-recvfrom o x [b e flags])  
fixnum? address
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0
(socket-recvfrom* o x [b e flags])  
fixnum? address
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
  flags : fixnum? = 0

Receive data into the buffer delimited by x[b e). Return the number of bytes read and, in the case of socket-recvfrom/socket-recvfrom* the peer address as a second value. For stream sockets, a value of 0 indicates a peer shutdown.

(socket-send-all o x [b e])  fixnum?
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)
(socket-recv-all o x [b e])  fixnum?
  o : socket?
  x : bytes?
  b : fixnum? = 0
  e : fixnum? = (bytes-length x)

Send (receive) all the data in the buffer delimited by x[b e), blocking if necessary. Return the number of bytes sent (received), which may be less than (- e b) if an error occurs or the peer has shutdown the socket.

(socket-send/port o inp [bufsz])  fixnum?
  o : socket?
  inp : input-port?
  bufsz : fixnum? = 4096
(socket-recv/port o outp [bufsz])  fixnum?
  o : socket?
  outp : output-port?
  bufsz : fixnum? = 4096

Copy the contents of a port to a socket (and vice versa) with a buffer size bufsz. Return the (total) number of bytes copied.

2.1.5 Port I/O

(socket-input-port o)  input-port?
  o : socket?
(socket-output-port o)  output-port?
  o : socket?

Create input and output ports tied to a stream socket.

(open-socket-stream peer)  
input-port? output-port?
  peer : address

Opens a client stream connected to peer. Returns input and output ports for the stream.

2.1.6 Control I/O

Supported only in UNIX-like systems

(socket-sendmsg o name data control [flags])  fixnum?
  o : socket?
  name : (or bytes? #f)
  data : (or bytes? #f)
  control : (or bytes? #f)
  flags : fixnum? = 0
(socket-sendmsg* o name data control [flags])  fixnum?
  o : socket?
  name : (or bytes? #f)
  data : (or bytes? #f)
  control : (or bytes? #f)
  flags : fixnum? = 0

Send a raw message with control parameters. Return the number of bytes written.

(socket-recvmsg o name data control [flags])  fixnum?
  o : socket?
  name : (or bytes? #f)
  data : (or bytes? #f)
  control : (or bytes? #f)
  flags : fixnum? = 0
(socket-recvmsg* o name data control [flags])  
fixnum?
(or fixnum? #f)
(or fixnum? #f)
fixnum?
  o : socket?
  name : (or bytes? #f)
  data : (or bytes? #f)
  control : (or bytes? #f)
  flags : fixnum? = 0

Receive a raw message with control parameters. Return 4 values:

2.1.7 Sockopts

(socket-getsockopt o level option)  any
  o : socket?
  level : fixnum?
  option : fixnum?
(socket-setsockopt o level option value)  void?
  o : socket?
  level : fixnum?
  option : fixnum?
  value : any

Performs getsockopt/setsockopt, translating between raw option values and scheme objects. See the file sockopt.in in the source distribution for the sockopts supported with value translation.

(socket-getsockopt-raw o level option value)  fixnum?
  o : socket?
  level : fixnum?
  option : fixnum?
  value : bytes?
(socket-setsockopt-raw o level option value)  void?
  o : socket?
  level : fixnum?
  option : fixnum?
  value : bytes?

Raw getsockopt/setsockopt.

2.1.8 Synchronization

(socket-recv-evt o)  evt?
  o : socket?

Create an event that is ready when data can be immediately received from the socket. The result of the synchronization is the event itself.

(socket-send-evt o)  evt?
  o : socket?

Create an event that is ready when data can be immediately sent through the socket. The result of the synchronization is the event itself.

(socket-connect-evt o)  evt?
  o : socket?

Create an event that is ready when an asynchronous connection initiated with socket-connect* completes. If the connection completes without error the result of the synchronization is the socket itself; if the connection fails the result is an exception.

(socket-accept-evt o)  evt?
  o : socket?

Creates an event that is ready when an connection can be accepted. The result of the synchronization is a new client socket if a connection is accepted successfully or an exception if the system fails to accept the new connection.

2.2 Addresses

Internet addresses (IPv4 and IPv6) are encapsulated in instances of a native inet-address type, while UNIX domain addresses are represented as a scheme path.

(inet-address family host port)  inet-address?
  family : fixnum?
  host : bytes?
  port : fixnum?
(inet-address family    
  host    
  port    
  flowinfo    
  scopeid)  inet-address?
  family : fixnum?
  host : bytes?
  port : fixnum?
  flowinfo : fixnum?
  scopeid : fixnum?

Raw inet-address constructor.

family must be AF_INET or AF_INET6. host must be a numeric ip address parseable by inet_pton. flowinfo and scopeid are only meaningful for IPv6 addresses.

(inet4-address host port)  inet-address?
  host : (or bytes? string?)
  port : fixnum?
(inet6-address host port ...)  inet-address?
  host : (or bytes? string?)
  port : fixnum?

Helper constructors for IPv4 and IPv6 addresses. If the host is a string, it is resolved using current-address-resolver, otherwise it is passed directly to the inet-address constructor.

(inet-address? o)  boolean?
  o : any
(inet4-address? o)  boolean?
  o : any
(inet6-address? o)  boolean?
  o : any

inet-address predicates

(inet-address-family o)  fixnum?
  o : inet-address?
(inet-address-host o)  bytes?
  o : inet-address?
(inet-address-port o)  fixnum?
  o : inet-address?

inet-address field extractors.

(inet-address=? o ...+)  boolean?
  o : inet-address?

inet-address equality test

(inet-address->vector o)  vector?
  o : inet-address?
(vector->inet-address o)  inet-address
  o : vector?

Convert an inet-address to/from a vector of the form #(AF_INET addr port) or #(AF_INET6 addr port flowinfo scopeid), suitable for marshalling.

(pack-address o)  bytes?
  o : address
(unpack-address o)  address
  o : bytes?

Raw address packing and unpacking. The binary representation is a direct copy of the underlying sockaddr struct, and thus platform-dependent. It is mainly useful for control I/O and sockopts.

(current-address-resolver)  (-> string? bytes?)
(current-address-resolver proc)  void?
  proc : (-> string? bytes?)

Parameter that specifies a resolver procedure. The resolver procedure must accept a string address and return a numeric address as a byte-string.

The defail resolver uses dns-get-address.

2.3 Exceptions

(struct exn:fail:socket (errno))
  errno : fixnum?

Subtype of of exn:fail:network. Instances are raised by the mzsocket API on syscall errors. errno contains the value of the system errno related to the error.

(exn:fail:socket:blocking? o)  boolean?
  o : any

True for instances of exn:fail:socket with error code EWOULDBLOCK.

2.4 Constants

2.4.1 Features

SOCKET_HAVE_RAW : boolean?

True if raw sockets are available.

SOCKET_HAVE_IPV6 : boolean?

True if IPv6 is available.

SOCKET_HAVE_UNIX : boolean?

True if UNIX domain sockets are available.

2.4.2 Fixed Addresses

INADDR_ANY : bytes?
INADDR_LOOPBACK : bytes?
INADDR_BROADCAST : bytes?
IN6ADDR_ANY : bytes?
IN6ADDR_LOOPBACK : bytes?

Fixed host addresses, provided as immutable byte strings.

2.4.3 Standard Constants

SHUT_RD : fixnum?
SHUT_WR : fixnum?
SHUT_RDWR : fixnum?
AF_UNSPEC : fixnum?
PF_UNSPEC : fixnum?
AF_INET : fixnum?
PF_INET : fixnum?
AF_INET6 : fixnum?
PF_INET6 : fixnum?
AF_UNIX : fixnum?
PF_UNIX : fixnum?
IPPROTO_IP : fixnum?
IPPROTO_IPV6 : fixnum?
IPPROTO_TCP : fixnum?
IPPROTO_UDP : fixnum?
IPPROTO_ICMP : fixnum?
IPPROTO_RAW : fixnum?
SOCK_STREAM : fixnum?
SOCK_DGRAM : fixnum?
SOCK_RAW : fixnum?
SOL_SOCKET : fixnum?
SO_ACCEPTCONN : fixnum?
SO_BROADCAST : fixnum?
SO_DEBUG : fixnum?
SO_DONTROUTE : fixnum?
SO_ERROR : fixnum?
SO_KEEPALIVE : fixnum?
SO_OOBLINE : fixnum?
SO_PASSCRED : fixnum?
SO_RCVBUF : fixnum?
SO_SNDBUF : fixnum?
SO_RCVLOWAT : fixnum?
SO_SNDLOWAT : fixnum?
SO_RCVTIMEO : fixnum?
SO_SNDTIMEO : fixnum?
SO_REUSEADDR : fixnum?
SO_REUSEPORT : fixnum?
SO_TYPE : fixnum?
SO_TIMESTAMP : fixnum?
SO_USELOOPBACK : fixnum?
IP_ADD_MEMBERSHIP : fixnum?
IP_DROP_MEMBERSHIP : fixnum?
IP_HDRINCL : fixnum?
IP_MTU : fixnum?
IP_MTU_DISCOVER : fixnum?
IP_MULTICAST_IF : fixnum?
IP_MULTICAST_LOOP : fixnum?
IP_MULTICAST_TTL : fixnum?
IP_OPTIONS : fixnum?
IP_PKTINFO : fixnum?
IP_RECVDSTADDR : fixnum?
IP_RECVIF : fixnum?
IP_RECVTOS : fixnum?
IP_RECVTTL : fixnum?
IP_TOS : fixnum?
IP_TTL : fixnum?
IPV6_ADD_MEMBERSHIP : fixnum?
IPV6_DROP_MEMBERSHIP : fixnum?
IPV6_MULTICAST_HOPS : fixnum?
IPV6_MULTICAST_IF : fixnum?
IPV6_MULTICAST_LOOP : fixnum?
IPV6_MTU : fixnum?
IPV6_MTU_DISCOVER : fixnum?
IPV6_CHECKSUM : fixnum?
IPV6_PKTINFO : fixnum?
IPV6_RECVERR : fixnum?
IPV6_UNICAST_HOPS : fixnum?
IPV6_RTHDR : fixnum?
IPV6_AUTHHDR : fixnum?
IPV6_DSTOPTS : fixnum?
IPV6_HOPOPTS : fixnum?
IPV6_FLOWINFO : fixnum?
IPV6_HOPLIMIT : fixnum?
TCP_KEEPALIVE : fixnum?
TCP_KEEPIDLE : fixnum?
TCP_KEEPINTVL : fixnum?
TCP_MAXRT : fixnum?
TCP_MAXSEG : fixnum?
TCP_NODELAY : fixnum?
TCP_SYNCNT : fixnum?
IP_PMTUDISC_WANT : fixnum?
IP_PMTUDISC_DONT : fixnum?
IP_PMTUDISC_DO : fixnum?
IPV6_PKTOPTIONS : fixnum?
IPTOS_LOWDELAY : fixnum?
IPTOS_THROUGHPUT : fixnum?
IPTOS_RELIABILITY : fixnum?
IPTOS_MINCOST : fixnum?
MSG_DONTROUTE : fixnum?
MSG_DONTWAIT : fixnum?
MSG_MORE : fixnum?
MSG_OOB : fixnum?

Standard system constants, depending on platform availability.

2.4.4 Error Codes

EACCES : fixnum?
EAFNOSUPPORT : fixnum?
EPFNOSUPPORT : fixnum?
EPROTONOSUPPORT : fixnum?
ENOBUFS : fixnum?
EFAULT : fixnum?
EADDRINUSE : fixnum?
EINVAL : fixnum?
ENOTSOCK : fixnum?
EOPNOTSUPP : fixnum?
EWOULDBLOCK : fixnum?
ECONNABORTED : fixnum?
EMFILE : fixnum?
ETIMEDOUT : fixnum?
ESOCKTNOSUPPORT : fixnum?
EALREADY : fixnum?
ECONNREFUSED : fixnum?
EISCONN : fixnum?
ENETUNREACH : fixnum?
ECONNRESET : fixnum?
EDESTADDRREQ : fixnum?
EMSGSIZE : fixnum?
ENOTCONN : fixnum?
EPROTOTYPE : fixnum?
ENOPROTOOPT : fixnum?
EINPROGRESS : fixnum?
EADDRNOTAVAIL : fixnum?
ENETDOWN : fixnum?
ENETRESET : fixnum?
ESHUTDOWN : fixnum?
EHOSTDOWN : fixnum?
EHOSTUNREACH : fixnum?
ENOMEM : fixnum?
ENFILE : fixnum?
EBADF : fixnum?
EPIPE : fixnum?

Standard error codes

3 Examples

3.1 A URL fetcher

A function that fetches a url and prints the result to the current output port:

  (require net/url net/dns)
  (define (get-url what)
    (let* ((url (string->url what))
           (host (dns-get-address (dns-find-nameserver) (url-host url)))
           (port (or (url-port url) 80))
           (sock (socket)))
      (socket-connect sock (inet4-address host port))
      (socket-send-all sock (url->request url))
      (socket-shutdown sock SHUT_WR)
      (socket-recv/port sock (current-output-port))
      (socket-close sock)))

To fetch googgle.com try:

  > (get-url "http://www.google.com")

The function uses standard library modules from the net collection and a trivial HTTP/1.0 request constructor:

  (define (url->request url)
    (string->bytes/utf-8 (format "GET ~a HTTP/1.0\r\n\r\n" (url->string url))))

The same function implemented using socket ports:

  (require scheme/port) ; for copy-port
  (define (get-url/stream what)
    (let* ((url (string->url what))
           (host (dns-get-address (dns-find-nameserver) (url-host url)))
           (port (or (url-port url) 80)))
      (let-values (((inp outp) (open-socket-stream (inet4-address host port))))
        (write-bytes (url->request url) outp)
        (close-output-port outp)
        (copy-port inp (current-output-port)))))

3.2 An echo server

A simple multi-threaded echo server implementation for stream sockets:

  (define (echo-server domain addr)
    (let ((sock (socket domain SOCK_STREAM)))
      (socket-setsockopt sock SOL_SOCKET SO_REUSEADDR #t)
      (socket-bind sock addr)
      (socket-listen sock 5)
      (let lp ()
        (let-values (((clisock cliaddr) (socket-accept sock)))
          (thread (lambda () (echo clisock cliaddr)))
          (lp)))))

Client connections are proceesed by the function echo:

  (define (echo sock addr)
    (let ((buf (make-bytes 4096)))
      (let lp ()
        (let ((ilen (socket-recv sock buf)))
          (unless (= ilen 0)
            (socket-send-all sock buf 0 ilen)
            (lp)))))
    (socket-close sock))

To run the server on port 5000:

  > (echo-server PF_INET (inet4-address INADDR_ANY 5000))

If you want to limit connections to localhost only, then bind to INADDR_LOOPBACK:

  > (echo-server PF_INET (inet4-address INADDR_LOOPBACK 5000))

You can now interact with the server via telnet:

  telnet localhost 5000

Or you can simply connect a port-pair to it from an mzscheme shell:

  > (let-values (((in out) (open-socket-stream (inet4-address #"127.0.0.1" 5000))))
      (write '(hello world) out)
      (read in))

=> (hello world)

The server can run on a unix domain socket as well:

  > (echo-server PF_UNIX (string->path "/tmp/echosrv"))

3.3 UDP echos

A UDP echo server:

  (define (udp-echo-server port)
    (let ((sock (socket PF_INET SOCK_DGRAM))
          (buf (make-bytes 1500)))
      (socket-setsockopt sock SOL_SOCKET SO_REUSEADDR #t)
      ; receive broadcasts too
      (socket-setsockopt sock SOL_SOCKET SO_BROADCAST #t)
      (socket-bind sock (inet4-address INADDR_ANY port))
      (let lp ()
        (let-values (((ilen peer) (socket-recvfrom sock buf)))
          (socket-sendto sock peer buf 0 ilen)
          (lp)))))

A function that sends a message to a udp-echo-server and waits for the reply with a timeout:

  (define (udp-echo-sendto dest timeout msg)
    (let* ((sock (socket PF_INET SOCK_DGRAM))
           (buf (make-bytes (bytes-length msg))))
      (socket-sendto sock dest msg)
      (sync/timeout timeout
        (handle-evt (socket-recv-evt sock)
          (lambda (x)
            (let-values (((ilen peer) (socket-recvfrom sock buf)))
              (values peer buf)))))))

A function that uses broadcast to find a udp echo server in the LAN:

  (define (udp-echo-find port timeout)
    (let* ((sock (socket PF_INET SOCK_DGRAM))
           (buf (make-bytes 8)))
      (socket-setsockopt sock SOL_SOCKET SO_BROADCAST #t)
      (socket-sendto sock (inet4-address INADDR_BROADCAST port) #"hello")
      (sync/timeout timeout
        (handle-evt (socket-recv-evt sock)
          (lambda (x)
            (let-values (((ilen peer) (socket-recvfrom sock buf))) peer))))))