48 lines
2.0 KiB
Common Lisp
48 lines
2.0 KiB
Common Lisp
(defvar *clients* '()
|
|
"This is a list of (socket :input status) which is used with
|
|
`socket:socket-status' to test for data ready on a socket.")
|
|
|
|
(defun echo-server (port)
|
|
"Listen on `port' for new client connections and for data arriving on
|
|
any existing client connections"
|
|
(let ((server (socket:socket-server port)))
|
|
(format t "Echo service listening on port ~a:~d~%"
|
|
(socket:socket-server-host server)
|
|
(socket:socket-server-port server))
|
|
(unwind-protect
|
|
(loop
|
|
(when (socket:socket-status server 0 1)
|
|
(echo-accept-client (socket:socket-accept server
|
|
:external-format :dos
|
|
:buffered t)))
|
|
(when *clients*
|
|
(socket:socket-status *clients* 0 1)
|
|
(mapcar #'(lambda (client)
|
|
(when (eq :input (cddr client))
|
|
(echo-service-client (car client)))
|
|
(when (eq :eof (cddr client))
|
|
(echo-close-client (car client)))) *clients*)))
|
|
(socket-server-close server))))
|
|
|
|
(defun echo-accept-client (socket)
|
|
"Accept a new client connection and add it to the watch list."
|
|
(multiple-value-bind
|
|
(host port) (socket:socket-stream-peer socket)
|
|
(format t "Connect from ~a:~d~%" host port))
|
|
(push (list socket :input nil) *clients*))
|
|
|
|
(defun echo-service-client (socket)
|
|
(let ((line (read-line socket nil nil)))
|
|
(princ line socket)
|
|
(finish-output socket)))
|
|
|
|
(defun echo-close-client (socket)
|
|
"Close a client connection and remove it from the watch list."
|
|
(multiple-value-bind
|
|
(host port) (socket:socket-stream-peer socket)
|
|
(format t "Closing connection from ~a:~d~%" host port))
|
|
(close socket)
|
|
(setq *clients* (remove socket *clients* :key #'car)))
|
|
|
|
(echo-server 12321)
|