Hello,
I have a rather SBCL specific question on reading and writing from
sockets.
I've been trying to figure out how to receive a connection from telnet
and both read and write to it.
At the moment, reading from it is fairly trivial using
socket-make-stream, but I can't seem to write to the stream using
format the way I would have expected, instead I get an error saying
that it is not a character output stream.
What is the appropriate way to send and receive text over a connection
like this?
Thanks
On Mon, 21 Aug 2006 14:08:05 -0700, ······@gmail.com wrote:
> Hello,
> I have a rather SBCL specific question on reading and writing from
> sockets.
>
> I've been trying to figure out how to receive a connection from telnet and
> both read and write to it.
Here is one way of doing this:
(defpackage :telnet-server
(:use :cl :sb-bsd-sockets)
(:import-from :sb-thread :destroy-thread :thread-alive-p))
(in-package :telnet-server)
(defmacro with-thread (name &body body)
"Defines a thread that executes `body'. Returns the thread-instance."
`(sb-thread:make-thread
(lambda ()
,@body)
:name ,name))
(defun default-handler (stream)
(write-line "incoming connection ...")
(format t "User said: ~A~%" (read-line stream)) (finish-output)
(format stream "Hello, this is the response from the server!~%"))
(defparameter *server-thread* nil)
(defun telnet-server (&key (host #(0 0 0 0)) (port 7221) (handler #'default-handler))
(when (and *server-thread* (thread-alive-p *server-thread*))
(ignore-errors (destroy-thread *server-thread*)))
(setf *server-thread*
(with-thread "server-thread"
(let ((server-socket (make-instance 'inet-socket :type :stream :protocol :tcp)))
(unwind-protect
(progn
(setf (sockopt-reuse-address server-socket) t)
(socket-bind server-socket host port)
(socket-listen server-socket 10)
(loop
(let ((incoming-stream
(socket-make-stream (socket-accept server-socket)
:output t :input t
:element-type :default
:external-format :utf-8
:buffering :none)))
(with-thread "incoming-stream"
(unwind-protect
(funcall handler incoming-stream)
(ignore-errors (close incoming-stream)))))))
(ignore-errors (socket-close server-socket)))))))
(export 'telnet-server)
For some reason the output generated in `default-handler'- which I
expected would go to the REPL-buffer - seems to go to the
`*inferiour-lisp*' buffer. I had this problem once before, but fixed it by
adding `(setf swank:*globally-redirect-io* t)' in `~/.swank.lisp' but this
doesn't seem to work anymore.
--
Lars Rune Nøstdal
http://lars.nostdal.org/