Jump to content

Echo server: Difference between revisions

→‎{{header|Common Lisp}}: added a proper usocket example. Removed my earlier actors-based example
(→‎{{header|Common Lisp}}: added a proper usocket example. Removed my earlier actors-based example)
Line 545:
 
=={{header|Common Lisp}}==
 
{{improve|Common Lisp|There should be a http://common-lisp.net/project/usocket/ example.}}
Here is a basic [http://common-lisp.net/project/usocket/ :usocket] example (it should work with any Common Lisp):
Sockets is not a standard part of Common Lisp but many implementations have support for this. The following example {{works with|CLISP}}
 
<lang lisp>(ql:quickload (list :usocket))
(defpackage :echo (:use :cl :usocket))
(in-package :echo)
 
(defun read-all (stream)
(loop for char = (read-char-no-hang stream nil :eof)
until (or (null char) (eq char :eof)) collect char into msg
finally (return (values msg char))))
 
(defun echo-server (port &optional (log-stream *standard-output*))
(let ((connections (list (socket-listen "127.0.0.1" port :reuse-address t))))
(unwind-protect
(loop (loop for ready in (wait-for-input connections :ready-only t)
do (if (typep ready 'stream-server-usocket)
(push (socket-accept ready) connections)
(let* ((stream (socket-stream ready))
(msg (concatenate 'string "You said: " (read-all stream))))
(format log-stream "Got message...~%")
(write-string msg stream)
(socket-close ready)
(setf connections (remove ready connections))))))
(loop for c in connections do (loop while (socket-close c))))))
 
(echo-server 12321)
</lang>
 
It's single threaded, so you can't REPL around with a running server. You'll need to start a second Lisp prompt, load the above and
 
<lang lisp>(defun echo-send (message port)
(with-client-socket (sock str "127.0.0.1" port)
(write-string message str)
(force-output str)
(when (wait-for-input sock :timeout 5)
(coerce (read-all str) 'string))))
 
(echo-send "Hello echo!" 12321)
</lang>
 
The return value of that call should be "You said: Hello echo!".
 
The usocket library notwithstanding, sockets are not a standard part of Common Lisp, but many implementations provide them. Here is a CLISP-specific example: {{works with|CLISP}}
<lang lisp>(defvar *clients* '()
"This is a list of (socket :input status) which is used with
Line 594 ⟶ 636:
 
(echo-server 12321)</lang>
 
Here is an actors-based example that uses the http://common-lisp.net/project/usocket/ library. {{works with|SBCL}}
 
<lang lisp>(defpackage :echo
(:use :cl :usocket :cl-actors)
(:import-from :cl-actors #:self))
(in-package :echo)
 
(defun read-line-no-hang (stream)
"Reads a line from stream. Returns a partial line rather than hanging."
(apply #'values
(loop for char = (read-char-no-hang stream nil :eof)
until (or (null char) (eq :eof char) (char= #\newline char))
collect char into str
finally (return (list (when str (coerce str 'string)) char)))))
 
(defactor tcp-server (server handler connections) (message)
(loop for ready in (wait-for-input (cons server connections) :ready-only t)
do (if (typep ready 'stream-server-usocket)
(push (socket-accept server) connections)
(multiple-value-bind (line last-char) (read-line-no-hang (socket-stream ready))
(when (eq last-char :eof)
(delete ready connections)
(socket-close ready))
(send handler ready line))))
(send self nil)
next)
 
(defactor echo-handler (stream) (socket input)
(format stream "~a~%" input)
(format (socket-stream socket) input)
next)
 
(defparameter +port+ 12321)
(defparameter *handler* (echo-handler :stream *standard-input*)
"Accepts and deals with socket messages.")
(defparameter *server*
(tcp-server :server (socket-listen "127.0.0.1" +port+)
:handler *handler*)
"Listens on the specified address+port. Passes socket input to specified handler.")
(send *server* :ping) ;; get the server started</lang>
 
In order to run this example, load the :cl-actors and :usocket libraries, start up a socket connection to 127.0.0.1:12321 and send something. In keeping with the theme, here's an actors-based way of doing it:
 
<lang lisp>
(defactor tcp-naive-client (sock) (message)
(format (socket-stream sock) message)
(force-output (socket-stream sock))
next)
 
(defparameter *client* (tcp-naive-client :sock (socket-connect "127.0.0.1" +port+)))
 
(send *client* "test~%test")
;; should print
;; test
;; test
 
(send *client* "test")
;; should print
;; test
 
(defparameter *client2* (tcp-naive-client :sock (socket-connect "127.0.0.1" +port+)))
 
(send *client2* "woo!")
;; should print
;; woo!
;; despite the fact that *client* isn't reading anything, and didn't terminate its last message with a newline
</lang>
 
=={{header|D}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.