The start-up-server
function starts a TCP server. Use mp:process-kill
to kill the server, and comm:open-tcp-stream
to send messages from another client to the server.
The function argument provides the name of the function that processes connections. When a connection is made function is called with the connected socket handle, at which point you can make a stream using make-instance
and communicate with the client. The server does not accept more connections until function returns, so normally it should create another light-weight process to handle the connection. However, the operating system typically provides a small queue of partially accepted connections, which prevents connection failure for new clients until the server is ready to accept more connections. If function is not specified the built-in Lisp listener server is used. See the examples section below.
The announce keyword causes a message to appear when the server is started. The value of this keyword is the stream to which the startup message is displayed.
The service argument specifies the name of the service. The location of the file specifying the names of services available varies, but typically on Windows 95 it is called SERVICES
and is stored in the Windows
directory., and on Windows NT it is the file
%SystemRoot%\system32\drivers\etc\SERVICES
The default value for service is lispworks
.
The process-name specifies the process name. The default is constructed from the service name in the following fashion:
(format nil "~S server" service)
The following example uses the built-in Lisp listener server:
(comm:start-up-server :service 10243)
It makes a Lisp listener server on port 10243 (check with local network managers that this port number is safe to use). When a client connects to this, Lisp calls read
. The client should send a string using Common Lisp syntax followed by a newline. This string is used to name a new light-weight process that runs a Lisp listener. When this has been created, the server waits for more connections.
The next example illustrates the use of the function argument. For each line of input read by the server it writes the line back with a message. The stream generates EOF
if the other end closes the connection.
(defvar *talk-port* 10244) ; a free TCP port number
(defun make-stream-and-talk (handle)
(let ((stream (make-instance 'comm:socket-stream
:socket handle
:direction :io
:element-type
'base-char)))
(mp:process-run-function (format nil "talk ~D"
handle)
'()
'talk-on-stream stream)))
(defun talk-on-stream (stream)
(unwind-protect
(loop for line = (read-line stream nil nil)
while line
do
(format stream "You sent: '~A'~%" line)
(force-output stream))
(close stream)))
(comm:start-up-server :function 'make-stream-and-talk
:service *talk-port*)
This is a client which uses the talk server:
(defun talking-to-myself ()
(with-open-stream
(talk (comm:open-tcp-stream "localhost"
*talk-port*))
(dolist (monolog
'("Hello self."
"Why don't you say something original?"
"Talk to you later then. Bye."))
(write-line monolog talk)
(force-output talk)
(format t "I said: \"~A\"~%"
monolog)
(format t "Self replied: \"~A\"~%"
(read-line talk nil nil)))))
(talking-to-myself)
=>
I said: "Hello self."
Self replied: "You sent: 'Hello self.'"
I said: "Why don't you say something original?"
Self replied: "You sent: 'Why don't you say something original?'"
I said: "Talk to you later then. Bye."
Self replied: "You sent: 'Talk to you later then. Bye.'"