Go to the tutorial main page.
The :sock module implements the socket interface in Allegro CL. It is documented in socket.htm.
A socket forms a bi-directional communication link between programs, usually over a network although that is not necessary. This tutorial shows briefly how to use the Allegro CL socket facility.
It is best to load a module when you know you will need it. (Often you will find the module is already loaded.)
cl-user(2): (require :sock)
In your source files, you would add the following:
(eval-when (compile eval load) (require :sock))
Now, you are ready to use it.
This will allow two lisps to send data between them. In this example Lisp One and Lisp Two can be the same lisp or two invocations of Lisp.
Begin by creating a passive socket. Here we let the operating system chose the port:
cl-user(1): (setq p (socket:make-socket :connect :passive)) #<multivalent stream socket waiting for connection at */40225 @ #x71b808ca> cl-user(2):
The operating system chose port 40225 (you will a likely see a different number, which you should use below). make-socket is documented here. This and other symbols naming socket functionality are in the socket package.
In Lisp Two create a new socket and connect to the passive socket:
cl-user(2): (setq a (socket:make-socket :remote-host "localhost" :remote-port 40225)) ;; Use the number ;; you got from the ;; above form in place ;; of 40225 #<multivalent stream socket connected from localhost/40226 to localhost/40225 @ #x71e5e09a> cl-user(3):
Create a new socket that is in the endpoint of this new connection.
cl-user(3): (setq b (socket:accept-connection p)) #<multivalent stream socket connected from localhost/40225 to localhost/40226 @ #x71e64c3a> cl-user(4):
Now in Lisp One we have passive socket p and active socket b. In Lisp Two we have active socket a. Other processes can continue to connect to passive socket p. Meanwhile active sockets a and b are connected to each other.
we send some data in the socket:
cl-user(4): (format a "hello ") nil cl-user(5): (force-output a) nil cl-user(6):
we read that data:
cl-user(6): (read b) hello cl-user(7):
and now send back data:
cl-user(7): (format b "bye ") nil cl-user(8): (force-output b) nil cl-user(9):
we read that message:
cl-user(10): (read a) bye cl-user(11):
You clean up as follows:
cl-user(10): (close p) #<multivalent stream socket closed, but was waiting for connection at */40225 @ #x71c24b0a> cl-user(11): (close b) t cl-user(12):
cl-user(12): (close a) t cl-user(13):
A server is a program that accepts connections over the network and performs a service. Here we've written a server that reads two numbers from the socket and writes the sum of the numbers back to the socket.
(defun sum-server (&key (port 9231)) (let ((p (socket:make-socket :connect :passive :local-port port))) (loop (let ((s (socket:accept-connection p))) (format s "~s" (+ (read s) (read s))) (close s)))))
Load that definition into a lisp and start it with:
Note that that form does not return. It just loops forever awaiting work. (You may want to run it in its own process with (mp:process-run-function :socket proc" #'sum-server).
In a second lisp define this client of the sum service:
(defun socket-sum (v1 v2 &key (host "localhost") (port 9231)) (let ((s (socket:make-socket :remote-host host :remote-port port))) (format s "~s ~s " v1 v2) (force-output s) (prog1 (read s) (close s))))
Now try some examples.
cl-user(3): (socket-sum 1 3) 4 cl-user(4): (socket-sum 1.234 3.23423) 4.4682302 cl-user(5): (socket-sum 3 (sqrt -1)) #C(3.0 1.0) cl-user(6):
Again, the socket interface documentation is in socket.htm.
Go to the tutorial main page.