2024-07-22
IPC via Unix domain sockets in Common Lisp
Netcat
The goal is to demonstrate how to replicate the behavior of netcat
.
From a shell process, start the server.
From another shell process, start the client, which takes data from standard input and outputs to the standard output of the server's process.
To stop the communication, kill the client.
To monitor network connections, run netstat -xa | grep /tmp/foo.socket
(valid for all sections).
Common Lisp
IOlib
From a REPL, start the server.
(asdf:load-system :iolib)
(defun start-server (&optional (path (uiop:native-namestring "/tmp/foo.socket")))
"Listen on PATH and print to `*standard-output*'."
(unwind-protect
(iolib:with-open-socket (s :address-family :local
:connect :passive
:local-filename path)
(iolib:with-accept-connection (client s)
(handler-case (loop (write-line (read-line client)))
(end-of-file () (format t "Client closed connection!~%")))))
(uiop:delete-file-if-exists path)))
(start-server)
From another REPL, start the client. Interrupt when done.
(asdf:load-system :iolib)
(defun client (&optional (path (uiop:native-namestring "/tmp/foo.socket")))
"Connect to server socket at PATH and send data from `*standard-input*'."
(iolib:with-open-socket (server :address-family :local
:remote-filename path)
(loop (write-line (read-line) server)
(finish-output server))))
(client)
SBCL's sb-bsd-sockets module
From a REPL, start the server.
(defun start-server (&optional (path (uiop:native-namestring "/tmp/foo.socket")))
"Listen on PATH and print to `*standard-output*'."
(let ((socket (make-instance 'sb-bsd-sockets:local-socket :type :stream)))
(sb-bsd-sockets:socket-bind socket path)
(sb-bsd-sockets:socket-listen socket 100)
(unwind-protect
;; Note that initializing the stream as below would fail since
;; `sb-bsd-sockets:socket-accept' returns a connected socket.
;; (sb-bsd-sockets:socket-make-stream socket :input t)
(with-open-stream (client (sb-bsd-sockets:socket-make-stream
(sb-bsd-sockets:socket-accept socket) :input t))
(handler-case (loop (write-line (read-line client)))
(end-of-file () (format t "Client closed connection!~%"))))
(uiop:delete-file-if-exists path))))
(start-server)
From another REPL, start the client. Interrupt when done.
(defun client (&optional (path (uiop:native-namestring "/tmp/foo.socket")))
"Connect to server socket at PATH and send data from `*standard-input*'."
(let ((socket (make-instance 'sb-bsd-sockets:local-socket :type :stream)))
(with-open-stream (server (sb-bsd-sockets:socket-make-stream socket :output t))
(sb-bsd-sockets:socket-connect socket path)
(loop (write-line (read-line) server)
(finish-output server)))))
(client)
Did you enjoy this article? Register for our newsletter to receive the latest hacker news from the world of Lisp and browsers!
- Maximum one email per month
- Unsubscribe at any time