Sockets

The socket is more versatile than other communication mechanisms because it can operate either host-locally (in unix domain) or network-widely (in internet domain). Connection-oriented socket (SOCK_STREAM) and unconnected socket (SOCK_DGRAM) are supported. In both cases, you must first create a socket address object by make-socket-address function, which returns an instance of socket-address. In unix domain, a socket address is specified by a path-name in the unix file system. In internet domain, the address is specified by combining the host machine name, the port number, and optionally the protocol number. If the port number is defined in /etc/services, it can be referred through the symbol specified by the service name. The function unix:getservbyname can be used to retrieve the port number from the symbolic service name. Port numbers less than 1024 are reserved for root users, and non-priviledged users are advised to use port numbers greater than 1024 for their private sockets.

Although connected streams provide bidirectional communication channels, the connection establishment operation is asymmetric. One endpoint is refered to server and other to client. The endpoint on the behalf of the server (service access point) must be first established. It is created by make-socket-port function which returns an instance of socket-port. The socket-port object is then used to accept connections from one or more clients by make-server-socket-stream. A call to make-server-socket-stream may be blocked until a connection request from a client really happens. Clients can make socket streams by make-client-socket-stream specifying a socket-address.

;;; an example of IPC through a socket stream:
;;; server side
(setq saddr  (make-socket-address :domain af_inet :host "etlic2" :port 2000))
(setq sport  (make-socket-port saddr))
(setq sstream (make-server-socket-stream sport))
;;;
;;; client side
(setq caddr (make-socket-address :domain af_inet :host "etlic2" :port 2000))
(setq cstream (make-client-socket-stream caddr))

In applications like a database or an environment simulator for mobile robots, multiple connection service between one server and many clients is required. This type of server can be programmed by the open-server function. From the current host name and given port number, open-server creates a socket port (service access point) on which connection requests are listened for. Since this port is attributed to be asynchronous, open-server is not blocked and returns immediately. Thereafter, each connection request interrupts EusLisp's main loop, and an socket-stream is created asynchronously. This socket-stream also works in asynchronous mode: the asynchronous input processing function which is the second argument to open-server is invoked whenever new data appear in this stream. Up to 30 connections can be established so that as many clients can access the server's data at the same time.

;; server side
(defun server-func (s) 
   (case (read s) ...    ;do appropriate jobs according to inputs
(open-server 3000 #'server-func)
... do other jobs in parallel
;; client-1 through client-N
(setq s (connect-server "etlmmd" 3000))
(format s "..." ...) (finish-output s)	;issue a command to the server
(read s)                                ;receive response

In contrast to the connection-oriented streams which provide reliable communication channels, the connectionless sockets are unreliable: messages may be lost, duplicated, and may arrive out-of-order. The connectionless sockets, however, have advantages that they do not need to assign file descriptor to each connection, and sending process is never blocked even if the receiver is not reading data and the buffer overflows.

To make connectionless sockets, use the following procedures. Messages are transferred by the unix:sendto and unix:recvfrom.

;;; receiver side
(setq saddr  (make-socket-address :domain af_inet :host "etlic2" :port 2001))
(setq sock   (make-dgram-socket saddr))
(unix:recvfrom sock)
;;;
;;; client side
(setq caddr (make-socket-address :domain af_inet :host "etlic2" :port 2001))
(setq sock (unix:socket (send caddr :domain) 2 0))
(unix:sendto sock caddr "this is a message")
;;;
;;; how to use echo service which is registered in /etc/services.
(setq caddr (make-socket-address :domain af_inet :host "etlic2"
                                 :port (car (unix:getservbyname "echo"))))
(setq echosock (unix:socket (send caddr :domain) 2 0))
(unix:sendto echosock caddr "this is a message")
(unix:recvfrom echosock)  --> "this is a message"



make-socket-address &key domain pathname host port proto service [function]

makes a sockaddr structure.


make-socket-port sockaddr [function]

makes a server-side socket port which is used to establish a connection with a client.


make-server-socket-stream sockport &optional (size 100) [function]

accepts a connection from a client and returns a two-way stream.


make-client-socket-stream sockaddr &optional (size 100) [function]

connects to a server port and returns a two-way stream.


open-server port remote-func [function]

prepares a socket port designated by the host name and port in internetnet domain, and waits for the connection requests asynchronously. Each time a connection is requested, it is accepted and a new socket-stream is opened. When a message arrives at the socket-port, remote-func is invoked with the socket port as the argument.


connect-server host port [function]

This is a shorhand of successive calls to make-socket-address and make-client-socket-stream. A socket-stream for a client to communicate with the server specified by host and port is returned. The port is made in internet domain.


k-okada 2013-05-21