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]
make-socket-port sockaddr [function]
make-server-socket-stream sockport &optional (size 100) [function]
make-client-socket-stream sockaddr &optional (size 100) [function]
open-server port remote-func [function]
connect-server host port [function]
k-okada 2013-05-21