Skip to content
tutorial 142 KiB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
             Network Programming in ANSI Common Lisp with IOLib
                   by: Peter Keller (psilord@cs.wisc.edu)
                               Version 0.0
                                4/02/2010


What is IOLib?
--------------

IOLib is a portable I/O library for ANSI Common Lisp. It includes socket
interfaces for network programming with IPV4/IPV6 TCP and UDP, an I/O
multiplexer that includes nonblocking I/O, a DNS resolver library, and a
pathname library.

Where do I get IOLib?
---------------------

The current version of IOLib is found here:

http://common-lisp.net/project/iolib/download.shtml

Please use the repository located in the Live Sources section for the most up
to date version of IOLib.

Introduction
------------

This tutorial loosely follows the exposition of network programming in "UNIX
Network Programming, Networking APIs: Sockets and XTI 2nd Edition" by W.
Richard Stevens. Many examples are derived from the source codes in that book.
Major deviations from the C sources include converting the concurrent examples
which use fork() into threaded examples which use the portable Bordeaux Threads
package, more structured implementations of certain concepts such as data
buffers and error handling, and general movement of coding style towards a
Common Lisp viewpoint.

The scope of this version of the tutorial is:
    0. Exposition suitable for programmers unfamiliar with ANSI Common Lisp
    1. IPV4 TCP
    2. Client/Server architecture
    3. Iterative vs Concurrent (via threading) vs Multiplexed Server Design
    4. Blocking and nonblocking I/O

It is intended, however, that this tutorial grows to contain the entirety of
IOLib's API as detailed in the Future Directions section of this tutorial. As
newer revisions of this tutorial are released, those gaps will be filled until
the whole of the IOLib API has been discussed.

Finally, the example code in this tutorial is algorithmically cut from the
actual example programs and inserted into the tutorial via a template
generation method. The example codes have embedded in them a tiny markup
language which facilitates this in the form (on a single line) of ';; ex-NNNb'
to begin an example section, and ';; ex-NNNe' to end an example section--NNN
stands for an enumeration integer for which each section's begin and end must
match.

Acknowledgements
----------------

I would like to greatly thank Stelian Ionescu, the author of IOLib
for his exposition of the various features of IOLib and his patience
in our sometimes long conversations.

Supporting Code
---------------

The file package.lisp contains a small library of codes used widely in the
examples. The supporting code implements:

    0. The package containing the examples, called :iolib.examples.

    1. The variables *host* and *port*, set to "localhost" and 9999
       respectively. This is the default name and port to which
       client connect and servers listen. Servers usually bind
       to 0.0.0.0, however.

    2. A small, but efficient, queue implementation, from "ANSI Common Lisp"
       by Paul Graham. The interface calls are:
       (make-queue)
       (enqueue obj q)
       (dequeue q)
       (empty-queue q)

    3. :iolib.examples currently depends upon IOLib alone and uses 
       packages :common-lisp, :iolib, and :bordeaux-threads.

Running the Examples
--------------------

These examples were developed and tested on SBCL 1.0.33.30 running on an x86
Ubuntu 8.10 machine. They were ran with two sessions of SBCL running, one
acting as a client, and the other as a server.

Supposing we'd like to start up the first example of the daytime server and
connect to it with the first daytime client example. Initially, the server will
bind to *host* and *port* and wait for the client to connect. We connect with
the client to *host* and *port*, get the time, and exit.

First we'll start up a server:

Linux black > sbcl
This is SBCL 1.0.33.30, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (require :iolib.examples) ; much output!
* (in-package :iolib.examples)

#<PACKAGE "IOLIB.EXAMPLES">
* (run-ex1-server)
Created socket: #<passive IPv4 stream socket, unbound {BF84B99}>[fd=5]
Bound socket: #<passive IPv4 stream socket bound to 0.0.0.0/9999 {BF84B99}>
Listening on socket bound to: 0.0.0.0:9999
Waiting to accept a connection...
[ server is waiting for the below client to connect! ]
Got a connection from 127.0.0.1:34794!
Sending the time...Sent!
T
*

Now we'll start up the client which connected to the above server:

Linux black > sbcl
This is SBCL 1.0.33.30, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (require :iolib.examples) ; much output!
* (in-package :iolib.examples)

#<PACKAGE "IOLIB.EXAMPLES">
* (run-ex1-client)
Connected to server 127.0.0.1:9999 via my local connection at 127.0.0.1:34794!
2/27/2010 13:51:48
T
*

In each client example, one can specify which host or port to which it should
connect:

* (run-ex1-client :host "localhost" :port 9999)
Connected to server 127.0.0.1:9999 via my local connection at 127.0.0.1:34798!
2/27/2010 13:53:7
T
*

The servers can be told a port they should listen upon and in this tutorial,
unless otherwise specified, will always bind to 0.0.0.0:9999 which means across
all interfaces on the machine and on port 9999.


                                   CHAPTER 1
                                   ---------
                             IPV4 TCP Client/Server
                          Blocking and nonblocking I/O

Overview of Examples
--------------------

The examples consist of a collection of clients and servers. They are split
into two groups: a set of daytime clients and server, and echo clients and
servers. In some of the examples, a certain network protocol, suppose
end-of-file handling, must be matched between client and server causing further
delineation.

Client protocols are matched to server protocols thusly:

Clients: ex1-client, ex2-client, ex3-client, can work
with servers: ex1-server, ex2-server, ex3-server, ex4-server.

Clients: ex4-client, ex5a-client, can work with servers: ex5-server,
ex6-server.

Clients: ex5b-client, can work with servers: ex7-server, ex8-server

Some clients and servers use the "daytime" series of protocols, those
are ex1-client, ex2-client, ex3-client, and ex1-server, ex2-server,
ex3-server, and ex4-server.

Some clients and servers use the "echo a line" series of protocols,
those are ex4-client, ex5a-client, ex5b-client, and ex5-server,
ex6-server, ex7-server, and ex8-server.

Even though much of the example source is included in the tutorial, it is
recommended that the example sources be carefully read and understood in order
to gain the most benefit from the tutorial.

Daytime Clients
---------------

In this section we show the evolution of a client which connects to a server
and gets the time of day. Each example shows some kind of an incremental
improvement to the previous one.

Daytime Client IVP4/TCP: ex1-client.lisp
----------------------------------------

This example is a very simple daytime client program which contacts a server,
by default at *host* and *port*, returns a single line of text that is the
current date and time, and then exits. It is written in more of a C style just
to make it easy to compare with similar simple examples in other languages. It
uses blocking, line oriented I/O.

The steps this program performs are:

0. The ex1-client.lisp entrance call:

+------------------------------------------------------------------------------+
|                                                                              |
(defun run-ex1-client (&key (host *host*) (port *port*))
|                                                                              |
+------------------------------------------------------------------------------+

1. Create an active TCP socket:

	The socket creation function (MAKE-SOCKET ...) is the method by which one
	creates a socket in IOLib.  It is very versatile and can be used to both
	create and initialize the socket in a single call.

	In this case, we use it simply and create an active IPV4 Internet stream
	socket which can read or write utf8 text and that understands a particular
	newline convention in the underlying data.

	One small, but important, deviation of IOLib sockets from Berkeley sockets
	is that when a socket is created, it is predestined to forever and
	unalterably be either an active or passive socket. Active sockets are used
	to connect to a server and passive sockets are used for a server's
	listening socket.

+------------------------------------------------------------------------------+
|                                                                              |
  ;; Create a internet TCP socket under IPV4
  (let ((socket
         (make-socket
          :connect :active
          :address-family :internet
          :type :stream
          :external-format '(:utf-8 :eol-style :crlf)
          :ipv6 nil)))
|                                                                              |
+------------------------------------------------------------------------------+

2. Specify the Server's IP address and port and establish a connection 
    with the server:

	This bit of code contains many calls into IOLib and we shall examine each
	of them. 

    The function LOOKUP-HOSTNAME takes as a string the DNS name
    for a machine and returns 4 values:
        A. an address
        B. a list of additional addresses(if existent)
        C. the canonical name of the host
        D. an alist of all the host's names with their respective addresses 

	We use only the first return value, the address component, to pass to the
	function CONNECT.

	The function CONNECT will connect the socket to the address, but to a
	random port if the :port keyword argument is not specified. The average
	client codes usually use :wait t to block until the connect can resolve
	with a connected fd or an error. The exception to always using :wait t is
	if the client needs to connect to many servers at once, suppose a web
	client, or if a server is also a client in other contexts and wishes not to
	block.

	The functions REMOTE-HOST and REMOTE-PORT return the ip address and port of
	the remote connection associated with the connected socket. LOCAL-HOST and
	LOCAL-PORT return the information of the client's end of the connected
	socket. Analogous calls REMOTE-NAME and LOCAL-NAME each return two values
	where the first value is the equivalent of *-host and the second value is
	the equivalent of *-port.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; do a blocking connect to the daytime server on the port.
    (connect socket (lookup-hostname host) :port port :wait t)
    (format t "Connected to server ~A:~A via my local connection at ~A:~A!~%"
            (remote-host socket) (remote-port socket)
            (local-host socket) (local-port socket))
|                                                                              |
+------------------------------------------------------------------------------+

3. Read and display the server's reply:

	Now that the socket has been connected to the server, the server will send
	a line of text to the client. The client uses the standard Common Lisp
	function READ-LINE to read the information from the socket. The function
	READ-LINE blocks and will only return when an *entire line* is read. Once
	read, the line is emitted to *standard-output* via the function call
	FORMAT.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; read the one line of information I need from the daytime
    ;; server.  I can use read-line here because this is a TCP socket.
    (let ((line (read-line socket)))
      (format t "~A" line))
|                                                                              |
+------------------------------------------------------------------------------+

4. End program:

	We close the socket with the standard function CLOSE and return true so the
	return value of this example is t.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; all done
    (close socket)
    t))
|                                                                              |
+------------------------------------------------------------------------------+

While this program works, it has some major flaws in it. First and foremost is
that it doesn't handle any conditions that IOLib signals in common use cases.
An example would be to run the ex1-client.lisp example without a daytime server
running. In most, if not all, Common Lisp toplevels, you'll be dropped into the
debugger on an unhandled SOCKET-CONNECTION-REFUSED-ERROR condition. Secondly,
it isn't written in the Common Lisp style.

Daytime Client IVP4/TCP: ex2-client.lisp
----------------------------------------

In this example, we simply tackle the fact ex1-server.lisp can be shortened
with an IOLib form to something where the application writer has less to do
concerning cleaning up the socket object. It also uses line oriented blocking
I/O.

The introduced macro WITH-OPEN-SOCKET calls MAKE-SOCKET with the arguments in
question and binds the socket to the variable 'socket'. When this form returns,
it will automatically close the socket.

This shortens the program so much, that the example can be included in its 
entirety:

+------------------------------------------------------------------------------+
|                                                                              |
(defun run-ex2-client (&key (host *host*) (port *port*))

  ;; We introduce with-open-socket here as a means to easily wrap
  ;; usually synchronous and blocking communication with a form that
  ;; ensures the socket is closed no matter how we exit it.
  (with-open-socket
      (socket :connect :active
              :address-family :internet
              :type :stream
              :external-format '(:utf-8 :eol-style :crlf)
              :ipv6 nil)

    ;; Do a blocking connect to the daytime server on the port.  We
    ;; also introduce lookup-hostname, which converts a hostname to an
    ;; 4 values, but in our case we only want the first, which is an
    ;; address.
    (connect socket (lookup-hostname host) :port port :wait t)
    (format t "Connected to server ~A:~A from my local connection at ~A:~A!~%"
            (remote-name socket) (remote-port socket)
            (local-name socket) (local-port socket))

    ;; read the one line of information I need from the daytime
    ;; server.  I can use read-line here because this is a TCP
    ;; socket. It will block until the whole line is read.
    (let ((line (read-line socket)))
      (format t "~A" line)
      t)))
|                                                                              |
+------------------------------------------------------------------------------+

This shorthand can go even further, if we add this to the WITH-OPEN-SOCKET
flags

    :remote-host (lookup-hostname host)
    :remote-port port

then the underlying MAKE-SOCKET call will in fact connect the socket directly
to the server before it is available for the body of the macro allowing us to
remove the connect call entirely! In the early examples, however, we don't
utilize IOLib's shorthand notations to this degree in order to make apparent
how the library maps into traditional socket concepts. After one gains
familiarity with the IOLib API, the situations where application of the
shortcuts are useful become much easier to see.

Daytime Client IVP4/TCP: ex3-client.lisp
----------------------------------------

Now we come to condition handling, which can moderately affect the layout of
your IOLib program. Any real program using IOLib must handle IOLib's signaled
conditions which are common to the boundary cases of network programming.
We've already seen one of these boundary cases when we tried to connect a
daytime client to a server that wasn't running.  The condition signaled in that
case was: SOCKET-CONNECTION-REFUSED-ERROR.  The stream interface has a set of
conditions which IOLib will signal, and another lower level IOLib layer--which
we'll come to in the nonblocking I/O examples have another set of conditions.
There is some intersection between them and we will explore that later. For
now, we'll just use the conditions associated with a stream.

Our rewrite of ex2-client.lisp into ex3-client.lisp (continuing to use line
oriented blocking I/O) proceeds thusly:

0. We create a helper function which connects to the server and reads the
    daytime line:

	Notice the HANDLER-CASE macro around the portion of the function which
	reads the date from the server. In looking at the boundary conditions from
	the server given this protocol, we can receive an END-OF-FILE condition if
	the client connected, but before the server could respond it exited,
	closing the connection. Since in this case we're inside of a
	WITH-OPEN-SOCKET form, we simply note that we got an END-OF-FILE and let
	the cleanup forms of WITH-OPEN-SOCKET close the connection. If we don't
	catch this condition, then the program will break into the debugger and
	that isn't useful.  It is usually debatable as to where one should handle
	conditions: either near to or far away from the generating calls. In these
	simple examples, no choice has any significant pros or cons. As your IOLib
	programs become more and more complex, however, it becomes more obvious at
	what abstraction level to handle signaled conditions.

+------------------------------------------------------------------------------+
|                                                                              |
(defun run-ex3-client-helper (host port)

  ;; Create a internet TCP socket under IPV4
  (with-open-socket
      (socket :connect :active
              :address-family :internet
              :type :stream
              :external-format '(:utf-8 :eol-style :crlf)
              :ipv6 nil)

    ;; do a blocking connect to the daytime server on the port.
    (connect socket (lookup-hostname host) :port port :wait t)
    (format t "Connected to server ~A:~A from my local connection at ~A:~A!~%"
            (remote-name socket) (remote-port socket)
            (local-name socket) (local-port socket))

    (handler-case
        ;; read the one line of information I need from the daytime
        ;; server.  I can use read-line here because this is a TCP
        ;; socket. It will block until the whole line is read.
        (let ((line (read-line socket)))
          (format t "~A" line)
          t)

      ;; However, let's notice the signaled condition if the server
      ;; went away prematurely...
      (end-of-file ()
        (format t "Got end-of-file. Server closed connection!")))))
|                                                                              |
+------------------------------------------------------------------------------+

1. Some conditions which are complete show-stoppers to the functioning of the
    code are caught at a higher level:

	Notice we catch the possible SOCKET-CONNECTION-REFUSED-ERROR from the
	connect inside of the function run-ex3-client-helper.

+------------------------------------------------------------------------------+
|                                                                              |
;; The main entry point into ex3-client
(defun run-ex3-client (&key (host *host*) (port *port*))
  (handler-case

      (run-ex3-client-helper host port)

    ;; handle a commonly signaled error...
    (socket-connection-refused-error ()
      (format t "Connection refused to ~A:~A. Maybe the server isn't running?~%"
              (lookup-hostname host) port))))
|                                                                              |
+------------------------------------------------------------------------------+

Here are some common conditions in IOLib (some from ANSI Common Lisp too) and
under what situations they are signaled.  In any IOLib program, *at least*
these conditions should be handled where appropriate.

END-OF-FILE:
    When a stream function such as READ, READ-LINE, etc...(but not
    RECEIVE-FROM), reads from a socket where the other end has been closed.

HANGUP:
    When writing to a socket with a stream function such as WRITE,
    FORMAT, etc...(but not SEND-TO), if the socket is closed then this
    condition is signaled.

SOCKET-CONNECTION-RESET-ERROR:
    When doing I/O on a socket and the other side of the socket sent a
    RST packet, this condition is signaled.  It can also happen with
    the IOLIb function ACCEPT and similar.

SOCKET-CONNECTION-REFUSED-ERROR:
    Signaled by connect if there is no server waiting to accept the incoming
    connection.


Daytime Servers
---------------

Now that we have completed the evolution of the daytime client, let's look at
the daytime servers.

The exposition of the servers follows in style of the clients.

Daytime Server IVP4/TCP: ex1-server.lisp
----------------------------------------

This first example is an iterative server which handles a single client and
then exits. The I/O is blocking and no error handling is performed.  This is
similar in scope to the ex1-client.lisp example.

0. Create the server socket:

	We see that the socket is :passive. Every socket in IOLib is predestined to
	be either an active or passive socket and since this is a server socket, it
	is passive. Also here we see that we can ask for the underlying fd of the
	socket with the function SOCKET-OS-FD.

+------------------------------------------------------------------------------+
|                                                                              |
(defun run-ex1-server (&key (port *port*))
  ;; Create a passive (server) TCP socket under IPV4 Sockets meant to
  ;; be listened upon *must* be created passively. This is a minor
  ;; deviation from the Berkeley socket interface.
  (let ((socket
         (make-socket
          :connect :passive
          :address-family :internet
          :type :stream
          :external-format '(:utf-8 :eol-style :crlf)
          :ipv6 nil)))
    (format t "Created socket: ~A[fd=~A]~%" socket (socket-os-fd socket))
|                                                                              |
+------------------------------------------------------------------------------+

1. Bind the socket

	Binding a socket is what gives it an endpoint to which clients can connect.
	The IOLib constant +IPV4-UNSPECIFIED+ represents 0.0.0.0 and means if a
	connection arrives on any interface, it will be accepted if it comes to the
	:port specified. The :reuse-addr keyword represents the socket option
	SO_REUSEADDR and states (among other things) that if the socket is in the
	TIME_WAIT state it can be reused immediately.  It is recommended that all
	servers use :reuse-addr on their listening socket.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; Bind the socket to all interfaces with specified port.
    (bind-address socket
                  +ipv4-unspecified+ ; which means INADDR_ANY or 0.0.0.0
                  :port port
                  :reuse-addr t)
    (format t "Bound socket: ~A~%" socket)
|                                                                              |
+------------------------------------------------------------------------------+

2. Listen on the socket

	Listening on a socket allows clients to connect. In this example, we've
	specified that 5 pending connection can be queued up in the kernel before
	being accepted by the process.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; Convert the sockxet to a listening socket
    (listen-on socket :backlog 5)
    (format t "Listening on socket bound to: ~A:~A~%"
            (local-host socket) (local-port socket))
|                                                                              |
+------------------------------------------------------------------------------+

3. Accept the client connection.

	Here we finally call the IOLib function ACCEPT-CONNECTION. We would like it
	to block, so we pass it :wait t. When ACCEPT-CONNECTION returns it will
	return a new socket which represents the connection to the client.
	ACCEPT-CONNECTION can return nil under some situations, such as on a slow
	server when the client sent a TCP RST packet in between the time the kernel
	sees the connection attempt and ACCEPT-CONNECTION is actually called.  We
	also opt to use the function REMOTE-NAME, which returns two values, the ip
	address and port of the remote side of the socket.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; Block on accepting a connection
    (format t "Waiting to accept a connection...~%")
    (let ((client (accept-connection socket :wait t)))
      (when client
        ;; When we get a new connection, show who it is from.
        (multiple-value-bind (who rport)
            (remote-name client)
          (format t "Got a connection from ~A:~A!~%" who rport))
|                                                                              |
+------------------------------------------------------------------------------+

4. Write the time to the client.

	Here we've figured out the time string and wrote it to the client.  Notice
	we call the function FINISH-OUTPUT. This ensures that all output is written
	to the client socket. For streams using blocking I/O, it is recommended
	that every write to a blocking socket be followed up with a call to
	FINISH-OUTPUT.

+------------------------------------------------------------------------------+
|                                                                              |
        ;; Since we're using a internet TCP stream, we can use format
        ;; with it. However, we should be sure to call finish-output on
        ;; the socket in order that all the data is sent. Also, this is
        ;; a blocking write.
        (multiple-value-bind (s m h d mon y)
            (get-decoded-time)
          (format t "Sending the time...")
          (format client "~A/~A/~A ~A:~A:~A~%" mon d y h m s)
          (finish-output client))
|                                                                              |
+------------------------------------------------------------------------------+

5. Close the connection to the client.

    We're done writing to the client, so close the connection so the client
	knows it got everything.

+------------------------------------------------------------------------------+
|                                                                              |
        ;; We're done talking to the client.
        (close client)
        (format t "Sent!~%"))
|                                                                              |
+------------------------------------------------------------------------------+

6. Close the server's socket.

	Since this is a one shot server, we close the listening socket and exit. In
	this and all other servers we call FINISH-OUTPUT to flush all pending
	message to *standard-output*, if any.

+------------------------------------------------------------------------------+
|                                                                              |
      ;; We're done with the server socket too.
      (close socket)
      (finish-output)
      t)))
|                                                                              |
+------------------------------------------------------------------------------+

The above code is the basic idea for how a very simple TCP blocking I/O server
functions. Like ex1-client, this server suffers from the inability to handle
common signaled conditions such as a HANGUP from the client--which means the
client went away before the server could write the time to it.

However, one major, and subtle, problem of this particular example is that the
socket to the client is *not immediately closed* if the server happens to exit,
say by going through the debugger back to toplevel--or a signaled condition,
before writing the date to the client. If this happens, it can take a VERY long
time for the socket to be garbage collected and closed. In this scenario, the
client will hang around waiting for data which will never come until the Lisp
implementation closes the socket when it gets around to collecting it. Garbage
collection is an extremely nice feature of Common Lisp, but non-memory OS
resources in general should be eagerly cleaned up.  Clients can suffer from
this problem too, leaving open, but unmanipulable, sockets to servers.

All clients or servers written against IOLib should either use some IOLib
specific macros to handle closing of socket, Common Lisp's condition system
like handler-case to catch the signaled conditions, or some other manual
solution.

Daytime Server IVP4/TCP: ex2-server.lisp
----------------------------------------

Similarly to ex2-client, this server uses the macro WITH-OPEN-SOCKET to open
the server socket. We introduce WITH-ACCEPT-CONNECTION to accept the client and
convert this server from a single shot server to an iterative server which can
handle, in a serial fashion only, multiple clients.

0. Serially accept and process clients:

	This portion of ex2-server shows the infinite loop around the accepting of
	the connection.  The macro WITH-ACCEPT-CONNECTION takes the server socket
	and introduces a new binding: client, which is the accepted connection. We
	ensure to tell the accept we'd like to be blocking. If for whatever reason
	we exit the body, it'll clean up the client socket automatically.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; Keep accepting connections forever.
    (loop
       (format t "Waiting to accept a connection...~%")

       ;; Using with-accept-connection, when this form returns it will
       ;; automatically close the client connection.
       (with-accept-connection (client server :wait t)
         ;; When we get a new connection, show who it is from.
         (multiple-value-bind (who rport)
             (remote-name client)
           (format t "Got a connnection from ~A:~A!~%" who rport))

         ;; Since we're using a internet TCP stream, we can use format
         ;; with it. However, we should be sure to finish-output in
         ;; order that all the data is sent.
         (multiple-value-bind (s m h d mon y)
             (get-decoded-time)
           (format t "Sending the time...")
           (format client "~A/~A/~A ~A:~A:~A~%" mon d y h m s)
           (finish-output client)
           (format t "Sent!~%")
           (finish-output)
           t)))))
|                                                                              |
+------------------------------------------------------------------------------+

For very simple blocking I/O servers like this one, serially accepting and
handling client connections isn't so much of a problem, but if the server does
anything which takes a lot of time or has to send lots of data back and forth
to many persistent clients, then this is a poor design. The means by which you
exit this server is by breaking evaluation and returning to the toplevel. When
this happens, the WITH-* forms automatically close the connection to the
client.

Daytime Server IVP4/TCP: ex3-server.lisp
----------------------------------------

In this iterative and blocking I/O server example, we add the handling of the
usual signaled conditions in network boundary cases often found with sockets.
Like the earlier client where we introduced HANDLER-CASE, this involves a
little bit of restructuring of the codes.

0. A helper function which opens a passive socket, binds it, and
    listens on it:

	There is nothing new in this portion of the code. We've seen this pattern
	before. In production code, we could probably shorten this further by
	having WITH-OPEN-SOCKET do the binding and connecting with appropriate
	keyword arguments.

+------------------------------------------------------------------------------+
|                                                                              |
(defun run-ex3-server-helper (port)
  (with-open-socket
      (server :connect :passive
              :address-family :internet
              :type :stream
              :ipv6 nil
              :external-format '(:utf-8 :eol-style :crlf))

    (format t "Created socket: ~A[fd=~A]~%" server (socket-os-fd server))

    ;; Bind the socket to all interfaces with specified port.
    (bind-address server +ipv4-unspecified+ :port port :reuse-addr t)
    (format t "Bound socket: ~A~%" server)

    ;; start listening on the server socket
    (listen-on server :backlog 5)
    (format t "Listening on socket bound to: ~A:~A~%"
            (local-host server)
            (local-port server))
|                                                                              |
+------------------------------------------------------------------------------+

1. Repeatedly handle clients in a serial fashion:

	The new material in this function is the HANDLER-CASE around sending the
	client the time information. The boundary conditions when writing to a
	client include the server getting a reset (RST) from the client or
	discovering the client had gone away and there is no-one to which to write.
	Since the write is contained within the WITH-ACCEPT-CONNECTION form, if any
	of these conditions happen, we simply notice that they happened and let the
	form clean up the socket when it exits.  If we didn't catch the conditions,
	however, we'd break into the debugger.

	One might ask what the value of catching these conditions here is at all
	since we don't actually do anything with them--other than printing a
	message and preventing the code from breaking into the debugger. For the
	purposes of the tutorial, it is intended that the reader induce the
	boundary cases manually and see the flow of the code and to understand
	exactly what conditions may be signaled under what conditions and how to
	structure code to deal with them. In production code where the author might
	not care about these conditions at all, one might simply ignore all the
	signaled conditions that writing to the client might cause.

	Of course, the appropriateness of ignoring network boundary conditions is
	best determined by context.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; keep accepting connections forever.
    (loop
       (format t "Waiting to accept a connection...~%")

       ;; Here we see with-accept-connection which simplifies closing
       ;; the client socket when are done with it.
       (with-accept-connection (client server :wait t)
         ;; When we get a new connection, show who it
         ;; is from.
         (multiple-value-bind (who rport)
             (remote-name client)
           (format t "Got a connnection from ~A:~A!~%" who rport))

         ;; Since we're using an internet TCP stream, we can use format
         ;; with it. However, we should be sure to finish-output in
         ;; order that all the data is sent.
         (multiple-value-bind (s m h d mon y)
             (get-decoded-time)
           (format t "Sending the time...")

           ;; Catch the condition of the client closing the connection.
           ;; Since we exist inside a with-accept-connection, the
           ;; socket will be automatically closed.
           (handler-case
               (progn
                 (format client "~A/~A/~A ~A:~A:~A~%" mon d y h m s)
                 (finish-output client))

             (socket-connection-reset-error ()
               (format t "Client reset connection!~%"))

             (hangup ()
               (format t "Client closed conection!~%")))

           (format t "Sent!~%"))))
|                                                                              |
+------------------------------------------------------------------------------+

2. End of the helper function, returns T to whomever called it:

+------------------------------------------------------------------------------+
|                                                                              |
    t))
|                                                                              |
+------------------------------------------------------------------------------+

3. The entry point into this example:

	We handle the condition SOCKET-ADDRESS-IN-USE-ERROR which is most commonly
	signaled when we try to bind a socket to address which already has a server
	running on it or when the address is in the TIME_WAIT state. The latter
	situation is so common--usually caused by a server just having exited and
	another one starting up to replace it, that when binding addresses, one
	should supply the keyword argument :reuse-addr with a true value to
	BIND-ADDRESS to allow binding a socket to an address in TIME_WAIT state.

+------------------------------------------------------------------------------+
|                                                                              |
;; This is the main entry point into the example 3 server.
(defun run-ex3-server (&key (port *port*))
  (handler-case

      (run-ex3-server-helper port)

    (socket-address-in-use-error ()
      ;; Here we catch a condition which represents trying to bind to
      ;; the same port before the first one has been released by the
      ;; kernel.  Generally this means you forgot to put ':reuse-addr
      ;; t' as an argument to bind address.
      (format t "Bind: Address already in use, forget :reuse-addr t?")))

  (finish-output))
|                                                                              |
+------------------------------------------------------------------------------+

Daytime Server IVP4/TCP: ex4-server.lisp
----------------------------------------

This is the first of our concurrent servers and the last of our daytime
protocol servers. Usually concurrency is introduced (in the UNIX environment)
with the fork() library call which creates an entirely new process with
copy-on-write semantics to handle the connection to the client. In this
tutorial environment, we've chosen to render this idea with the portable
threading library Bordeaux Threads.  The I/O is still line oriented and
blocking, however, when a thread blocks another can run giving the illusion of
a server handling multiple clients in a non-blocking fashion.

We also introduce UNWIND-PROTECT ensures that various sockets are closed under
various boundary conditions in the execution of the server.  An UNWIND-PROTECT
executes a single form, and after the evaluation, or interruption, of that
form, evaluates a special cleanup form. The cleanup form is *always* evaluated
and we use this to cleanup non-memory system resources like sockets.

Threads present their own special problems in the design of a server. Two
important problems are: data races and thread termination. The tutorial tries
very hard to avoid any data races in the examples and this problem is
ultimately solvable using Bordeaux-Threads mutexes or condition variables.  Our
simple examples do not need mutexes as they do not share any data between
themselves. 

The harder problem is thread termination. Since the tutorial encourages
experimentation with the clients and servers in a REPL, threads may leak when
the server process' initial thread stops execution and goes back to the REPL.
We use three API calls from the Bordeaux Threads: THREAD-ALIVE-P, ALL-THREADS,
and DESTROY-THREAD--which are not to be used in normal thread programming.  We
do this here in order to try and clean up leaked threads so the clients know
immediately when the server process stopped and we don't pollute the REPL with
an ever increasing number of executing threads. The employed method of
destroying the threads, on SBCL specifically, allows the invocation of the
thread's UNWIND-PROTECT's cleanup form, which closes the socket to the client
before destroying the thread.  On other implementations of Common Lisp, we are
not guaranteed that the thread's UNWIND-PROTECT cleanup form will be evaluated
when we destroy it.

This method is also extremely heavy handed in that it uses the function
IGNORE-ERRORS to ignore any condition that Bordeaux Thread's DESTROY-THREAD may
have signaled, including important conditions like HEAP-EXHAUSTED-ERROR, an
SBCL specific condition. In a real threaded server, the exiting of the initial
thread (which means exiting of the runtime and termination of the entire Lisp
process) will destroy all other threads as the process tears itself down and
exits. This is the recommended way a threaded server should exit.

Since threading is implementation dependent for what guarantees are provided,
any non-toy threaded network server will probably use the native implementation
of threads for a specific Common Lisp implementation.  An example difficult
situation would be trying to terminate a thread which is blocked on I/O.
Different implementations would handle this in different ways.

The two provided examples, ex4-server and ex5-server, provide a general idea
for the structuring of the code to utilize threads.

Here is the dissection of ex4-server:

0. A special variable which will allow the initial thread to pass a client
    socket to a thread handling said client:

+------------------------------------------------------------------------------+
|                                                                              |
;; This variable is the means by which we transmit the client socket from
;; the initial thread to the particular thread which will handle that client.
(defvar *ex4-tls-client* nil)
|                                                                              |
+------------------------------------------------------------------------------+

1. A helper function which begins with the usual recipe for a server:

+------------------------------------------------------------------------------+
|                                                                              |
(defun run-ex4-server-helper (port)
  (with-open-socket
      (server :connect :passive
              :address-family :internet
              :type :stream
              :ipv6 nil
              :external-format '(:utf-8 :eol-style :crlf))

    (format t "Created socket: ~A[fd=~A]~%" server (socket-os-fd server))

    ;; Bind the socket to all interfaces with specified port.
    (bind-address server +ipv4-unspecified+ :port port :reuse-addr t)
    (format t "Bound socket: ~A~%" server)

    ;; start listening on the server socket
    (listen-on server :backlog 5)
    (format t "Listening on socket bound to: ~A:~A~%"
            (local-host server)
            (local-port server))
|                                                                              |
+------------------------------------------------------------------------------+

2. Forever more, accept a client connection on the listening socket
    and start a thread which handles it:

	There is a lot going on in this piece of code. The first thing to notice is
	the UNWIND-PROTECT and its cleanup form. The form which UNWIND-PROTECT is
	guarding is an infinite loop which does a blocking accept to get a client
	socket, rebinds *default-special-bindings* adding to its assoc list the
	binding for *ex4-tls-client*, and creates a thread which handles the
	client.

	The cleanup form walks all of the active client threads and destroys them,
	ignoring any conditions that may have arose while doing so. Destroying the
	threads prevents them from piling up and eventually causing havoc if many
	servers start and exit over time. In addition, it forces an eager close on
	the client sockets allowing any clients to know the server went away
	immediately.

+------------------------------------------------------------------------------+
|                                                                              |
    ;; Here we introduce unwind-protect to ensure we properly clean up
    ;; any leftover threads when the server exits for whatever reason.
    ;; keep accepting connections forever, but if this exits for
    ;; whatever reason ensure to destroy any remaining running
    ;; threads.
    (unwind-protect
         (loop                         ; keep accepting connections...
            (format t "Waiting to accept a connection...~%")
            (finish-output)
            (let* ((client (accept-connection server :wait t))
                   ;; set up the special variable according to the
                   ;; needs of the Bordeaux Threads package to pass in
                   ;; the client socket we accepted to the about to be
                   ;; created thread.  *default-special-bindings* must
                   ;; not be modified, so here we just push a new scope
                   ;; onto it.
                   (*default-special-bindings*
                    (acons '*ex4-tls-client* client
                           *default-special-bindings*)))

              ;; ...and handle the connection!
              (when client
                (make-thread #'process-ex4-client-thread
                             :name 'process-ex4-client-thread))))