USOCKET API documentation

$Id: api-docs.shtml 558 2010-09-15 03:35:27Z ctian $
Work in progress.

Please note that we're committed to the interface described below for the entire 0.x phase of the library. When 1.0 comes some of the functionality may be split up in different functions and guarantees may change because of it.

Conventions

Specification of a host or local-host parameter
A host or local-host parameter may be any one of

Functions for socket creation and manipulation

socket-connect host port &key protocol element-type timeout deadline nodelay local-host local-port => socket

Creates a TCP (stream) or UDP (datagram) socket to the host and port specified. The return value is a socket object of class stream-usocket, or datagram-usocket.

protocol should be :stream (default) or :datagram, which means TCP or UDP (Start from USOCKET 0.5)
element-type argument is used in the construction of the associated stream, i.e. 'character or '(unsigned-byte 8), only used by TCP.
timeout is a integer, it represents the socket option SO_RCVTIMEO (read timeout), in seconds.
deadline is only supported in Clozure CL and Digitool MCL, look up their documents please.
local-host and local-port, when specified, will cause the socket calling bind() on local address. This is useful for selecting interfaces to send, or listening on UDP port. Note: use only one of them are allowed when reasonable (listen on wildcard address, or bind to random free port).

nodelay Allows to disable/enable Nagle's algorithm (http://en.wikipedia.org/wiki/Nagle%27s_algorithm).
If this parameter is omitted, the behaviour is inherited from the CL implementation (in most cases, Nagle's algorithm is enabled by default, but for example in ACL it is disabled).
If the parmeter is specified, one of these three values is possible:


socket-listen host port &key reuse-address backlog element-type => socket

Creates and returns a passive ("server") socket associated with host and port. The object returned is of subtype stream-server-usocket.

host names a local interface.
port names a local port, or 0 (zero) to request a random free port.
reuse-address is a boolean (t, nil) value signalling reuse of the address is requested (or not).
backlog is the length of the queue containing connections which haven't actually been accepted yet.
element-type is the default element type used for sockets created by socket-accept. character is the default when it's not explicitly provided.

socket-accept socket &key element-type => new-socket

Creates and returns an active ("connected") stream socket new-socket from the socket passed. The return value is a socket object of class stream-usocket.

element-type is the element type used to construct the associated stream. If it's not specified, the element-type of socket (as used when it was created by the call to socket-listen) is used.

socket-close socket

Flushes the stream associated with the socket and closes the socket connection.

get-local-name socket => address, port
get-local-address socket => address
get-local-port socket => port

Returns the local address and/or port information of socket.

get-peer-name socket => address, port
get-peer-address socket => address
get-peer-port socket => port

Returns the remote address and/or port information of socket. The socket passed to this function must be a connected socket.

socket-send socket buffer length &key host port

Send a (unsigned-byte 8) data buffer to a datagram socket, and return the number of bytes sent. (Start from USOCKET 0.5)

socket should be a datagram-usocket.
buffer is a Lisp vector, type of (simple-array (unsigned-byte 8) *).
length is used to tell socket-send the actual useful length of data buffer for sending to socket.
host and port are used for unconnected datagram sockets, for sending to specific destination.

socket-receive socket buffer length

Receive data from a datagram socket, and return 4 values: return-buffer, return-length, remote-host, and remove-port. If the datagram socket was created by socket-connect with a timeout keyword argument, this function will block at most that timeout value (in seconds). (Start from USOCKET 0.5)

socket should be a datagram-usocket.
buffer is a Lisp vector, type of (simple-array (unsigned-byte 8) *). Using nil here is also allowed, new buffer will be created to hold data.
length is used to specify the length of a exist buffer for receiving at most these data. Using nil here is allowed, and the actual length of buffer will be used; when buffer is also nil, a default maximum length (65507) will be used. 

socket-shutdown socket direction

The socket-shutdown call causes all or part of a full-duplex connection on the socket associated with sockfd to be shut down. If direction is :input, further receptions will be disallowed. If direction is :output, further transmissions will be disallowed. If direction is :io, further receptions and transmissions will be disallowed. (Starting from USOCKET 0.6.4)

socket should be a datagram-usocket.
direction should be either :input, :output or :io.

wait-for-input socket-or-sockets &key timeout ready-only

Waiting on one or multiple sockets for given time, and returns once some of them are available of reading data. This is like UNIX's "select" function.

It returns two values: the first is the list of sockets which are readable (or in case of server sockets acceptable). nil may be returned for this value either when waiting timed out or when it was interrupted (EINTR).  The second value is a real number indicating the time remaining within the timeout period or nil if none.

Without the ready-only argument, WAIT-FOR-INPUT will return all sockets in the original list you passed it. This prevents a new list from being consed up. Some users of USOCKET were reluctant to use it if it wouldn't behave that way, expecting it to cost significant performance to do the associated garbage collection.

Without the ready-only arg, you need to check the socket STATE slot for the values documented in usocket class.

socket-server host port function &optional arguments &key in-new-thread protocol timeout max-buffer-size element-type reuse-address multi-threading

Create a simple TCP or UDP socket server. (Start from USOCKET 0.5)

host names a local interface,
port names a local port,
function names a function object, which is used to handle TCP or UDP connections, the actual API of this function will be explained later.
arguments is a list used for passing extra arguments to user-defined function.
in-new-thread is a boolean, default is nil. When it's T, the server will be created in a new thread and socket-server returns immediately in current thread.
protocol could be either :stream (default) or :datagram, which decide the socket server is TCP server or UDP server.
timeout is UDP only, it provides the internal socket-receive call (in UDP event loop of the socket server) a read timeout, default value is 1 (second).
max-buffer-size is UDP only, it's the max UDP data buffer size when handling UDP packets, default value is 65507.
element-type is TCP only, it's element-type of the stream provided for user-defined function,
reuse-address is TCP only, it's a boolean option for internal call of socket-listen in the socket server,
multi-threading is TCP only, it's a boolean, default value is nil. When it's T, each client connection will cause a new thread being created to handle that client, so that the TCP server could handle multiple clients at the same time. (Note: since UDP server is connectionless, it can always handle multiple clients, as long as the handler function run fast enough)

The handler function for TCP is stream-based. A template function is this one:

(defun default-tcp-handler (stream) ; null
(declare (type stream stream))
(terpri stream))

Note: 1. you don't need to close the stream as socket-server will do that for you. 2. More function arguments can be defined, and these extra arguments must be feeded as the optional arguments of socket-server.

The handler function for UDP is buffer-based, that is, you receive a buffer of data as input, and you return another buffer for output. A template function is a simple UDP echo server:

(defun default-udp-handler (buffer) ; echo
(declare (type (simple-array (unsigned-byte 8) *) buffer))
buffer)

Note: 1. data length is the length of the whole buffer. 2. Sometimes you may want to know the client's IP address and sending port, these informations are specially bounded on variables *remote-host* and *remote-port* when handler function is running.

Classes

usocket
Slots:
socket :accessor socket

Used to store sockets as used by the current implementation - may be any of socket handles, socket objects and stream objects

state :accessor state

Used to store socket state: NIL (not ready), :READ (ready to read).

stream-usocket
Parent classes: usocket
Slots:
stream :accessor socket-stream

Used to store the stream associated with the tcp socket connection.
When you want to write to the socket stream, use this function.

stream-server-usocket
Parent classes: usocket
Slots:
element-type :reader element-type

Indicates the default element-type to be used when constructing streams off this socket when no element type is specified in the call to socket-accept.

datagram-usocket (Start from USOCKET 0.5)
Parent classes: usocket
Slots:
connected-p :accessor connected-p

Used to identify if the datagram is connected. It will be setup by socket-connect, and used by socket-send and socket-receive.

Variables / constants

*wildcard-host*

The host to use with socket-listen to make the socket listen on all available interfaces.

*auto-port*

The port number to use with socket-listen to make the socket listen on a random available port. The port number assigned can be retrieved from the returned socket by calling get-local-port.

*remote-host*

Special variable used in socket-server's handler function for getting current client address. (Start from USOCKET 0.5)

*remote-port*

Special variable used in socket-server's handler function for getting current client port. (Start from USOCKET 0.5)

How do I ...

... force the output to be written to the network?
When you write output to the stream, it may be buffered before sent over the network - for optimal performance of small writes. You can force the buffer to be flushed the same way as with normal streams:
(format (socket-stream socket) "Hello there~%")   ;; output into buffers
(force-output (socket-stream socket)) ;; <== flush the buffers, if any
... check whether the other end has closed my socket stream?
Reading from a stream which has been closed at the remote end signals an END-OF-FILE condition, meaning that reading from the stream and detecting that condition is the way to do it.
... check whether reading from a socket stream will block?
When you want to check one stream for readiness of input, call the listen function on the stream object associated with the socket.
Example:
(listen (usocket:socket-stream your-socket))
==> NIL (if no input is available)
... wait for input to become available on (at least) one stream (of a set)
Currently, that's hard to do efficiently if you want to use releases. The next minor release (0.4.0) will include this functionality and for all platforms (except SBCL and LispWorks; both Win32) it's already available in trunk (svn://common-lisp.net/project/usocket/svn/usocket/trunk).
If you want to use this code you're most welcome and feedback is appreciated.
Example to be used with trunk:
(usocket:wait-for-input (list socket1 socket2 socket3) :timeout <your optional timeout value>)
==> list-of-sockets-to-read-from
... convert my existing trivial-sockets based application to usocket?
There are actually 3 answers to that question.
  1. Rewrite your code to keep a usocket object instead of the stream object returned by trivial-sockets.
  2. The quick conversion with the good performance characteristics (use only when you don't want to use the socket object):
    Replace all your invocations of
      (trivial-sockets:open-socket-stream ....)

    with
    (usocket:socket-stream (usocket:socket-connect ...))
    And replace all invocations of
      (trivial-sockets:socket-accept ...)

    with
    (usocket:socket-stream (usocket:socket-accept ...))
    And replace all invocations of
      (trivial-sockets:open-server ...)

    with
    (usocket:socket-listen ...)
  3. And the last option which provides a compatible (but slower, because it uses Gray streams) interface is to use trivial-usocket.
    The trivial-usocket package provides a 1-1 mapped interface to trivial-sockets, but uses Gray streams; that way, it's later possible to retrieve the socket object from the stream returned and to use that socket for other usocket operations. Use this approach as a migration path where you're not rewriting your application at once, but in small steps.
Back to Common-lisp.net.
Valid XHTML 1.0 Strict