When a port is returned from one of these calls it is unbuffered. This allows both reading and writing to the same port to work. If you want buffered ports you can (assuming sock-port is a socket i/o port):
(require 'i/o-extensions) (define i-port (duplicate-port sock-port "r")) (define o-port (duplicate-port sock-port "w"))
Returns a SOCK_STREAM socket of type family using
protocol. If family has the value AF_INET,
SO_REUSEADDR will be set. The integer argument protocol
corresponds to the integer protocol numbers returned (as vector
elements) from (getproto). If the protocol argument is not
supplied, the default (0) for the specified family is used. SCM
sockets look like ports opened for neither reading nor writing.
Returns a pair (cons) of connected SOCK_STREAM (socket) ports of
type family using protocol. Many systems support only
socketpairs of the af-unix family. The integer argument
protocol corresponds to the integer protocol numbers returned (as
vector elements) from (getproto). If the protocol argument is
not supplied, the default (0) for the specified family is used.
Socket:shutdown returns socket if successful, #f if
not.
#f if not
successful.
#f if not successful. Binding a
unix-socket creates a socket in the file system that must be
deleted by the caller when it is no longer needed (using
delete-file).
#f if not.
socket:listen can
be polled for connections by char-ready? (see char-ready?). This avoids blocking on connections by
socket:accept.
The following example is not too complicated, yet shows the use of sockets for multiple connections without input blocking.
;;;; Scheme chat server
;;; This program implements a simple `chat' server which accepts
;;; connections from multiple clients, and sends to all clients any
;;; characters received from any client.
;;; To connect to chat `telnet localhost 8001'
(require 'socket)
(require 'i/o-extensions)
(let ((listener-socket (socket:bind (make-stream-socket af_inet) 8001))
(connections '()))
(socket:listen listener-socket 5)
(do () (#f)
(cond ((char-ready? listener-socket)
(let ((con (socket:accept listener-socket)))
(display "accepting connection from ")
(display (getpeername con))
(newline)
(set! connections (cons con connections))
(display "connected" con)
(newline con))))
(set! connections
(let next ((con-list connections))
(cond ((null? con-list) '())
(else
(let ((con (car con-list)))
(cond ((char-ready? con)
(let ((c (read-char con)))
(cond ((eof-object? c)
(display "closing connection from ")
(display (getpeername con))
(newline)
(close-port con)
(next (cdr con-list)))
(else
(for-each (lambda (con)
(file-set-position con 0)
(write-char c con)
(file-set-position con 0))
connections)
(cons con (next (cdr con-list)))))))
(else (cons con (next (cdr con-list))))))))))))
You can use `telnet localhost 8001' to connect to the chat server,
or you can use a client written in scheme:
;;;; Scheme chat client
;;; this program connects to socket 8001. It then sends all
;;; characters from current-input-port to the socket and sends all
;;; characters from the socket to current-output-port.
(require 'socket)
(require 'i/o-extensions)
(define con (make-stream-socket af_inet))
(set! con (socket:connect con (inet:string->address "localhost") 8001))
(do ((cs #f (and (char-ready? con) (read-char con)))
(ct #f (and (char-ready?) (read-char))))
((or (eof-object? cs) (eof-object? ct))
(close-port con))
(cond (cs (display cs)))
(cond (ct (file-set-position con 0)
(display ct con)
(file-set-position con 0))))