Socket Tutorial

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.

Quick Start

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.

Making a socket connection

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.

In Lisp One:

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

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): 

Back in Lisp One:

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.

In Lisp Two

we send some data in the socket:

cl-user(4): (format a "hello ")
nil
cl-user(5): (force-output a)
nil
cl-user(6): 

In Lisp One

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): 

Back in Lisp Two

we read that message:

cl-user(10): (read a)
bye
cl-user(11): 

Cleaning up when you are done

You clean up as follows:

In Lisp One:

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): 

In Lisp Two:

cl-user(12): (close a)
t
cl-user(13): 

A Simple Server

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:

cl-user(14): (sum-server)

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.