From: Dragontamer
Subject: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <c74e06c48254702543d934ae4c012de3@localhost.talkaboutprogramming.com>
Hi, i am attempting to write a mud (in clisp), but i have stumbled upon a problem.

Muds require to accept multiple connections into one port (or so it seems). How do you do that? 

Thx in advance.

From: Philippe Brochard
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <87hdytdki6.fsf@free.fr>
"Dragontamer" <··@dragontamer.is-a-geek.com> writes:

> Hi, i am attempting to write a mud (in clisp), but i have stumbled 
>upon a problem.
> 
> Muds require to accept multiple connections into one port (or so it seems).
> How do you do that? 
> 
> Thx in advance.
> 
Hi,

I've made this little test code under clisp.
Maybe you can find it useful.

----------------------------------------------------------------------
(defvar *all-clients* '())
(defvar *port* 25555)

(defun close-and-quit ()
  (format t "End of connexion~%")
  (dolist (client *all-clients*)
    (close client))
  (socket-server-close sock)
  (quit))

(defun client-quit (client)
  (format t "client has quit : ~A~%" client)
  (format client "Bye...~%")
  (close client)
  (setq *all-clients* (remove client *all-clients*)))

(defun info-on-server (client)
  (format client "There is ~A client connected to the server~%"
	  (length *all-clients*))
  (format client "sockets = ~A~%" *all-clients*))

(defun send-to-all (client str)
  (format t "~A~%" str)
  (dolist (cl *all-clients*)
    (unless (eq client cl)
      (when (nth-value 1 (ignore-errors (format cl "~A~%" str)))
	(client-quit cl)))))

(defun read-command (client)
  (let ((str (read-line client)))
    (cond ((string-equal str "") nil)
	  ((string-equal str "quit") (client-quit client))
	  ((string-equal str "close") (close-and-quit))
	  ((string-equal str "info") (info-on-server client))
	  (t (send-to-all client str)))))

(format t "Start serveur on port ~A~%" *port*)
(setq sock (socket-server *port*))

(loop
 (when (socket-wait sock 0 1)
   (let ((new-sock (socket-accept sock)))
     (push new-sock *all-clients*)
     (format t "New connexion: ~A~%" *all-clients*)
     (format new-sock "Welcome! commands are quit/close/info
Everything else is send to all clients.~%")))
 (dolist (client *all-clients*)
   (when (listen client)
     (read-command client))))
----------------------------------------------------------------------

-- 
Philippe Brochard    <hocwp _CHEZ_ free.fr>
                      http://hocwp.free.fr
From: Yang, Chul-woong
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <PJJOb.24943$T3.375825@news.bora.net>
I'm in same situation with dragontamer. (i'm lisp newbie)
Philippe's answer is very helpful, thx.

Anyway, are there any simple network server example code with
thread/process model in clisp/sbcl?
(i.e. listen(), accept(), fork() or pthread_create() model in C.
 Phillipe's code seems to be listen(), accept() and select() model.)

Tried to find anything in web, but no success. (i guess that http.lsp in
clisp will be
helpful, but links have gone)
--
Yang, Chul-Woong
······@dbserver.kaist.ac.kr

"Philippe Brochard" <·····@free.fr> wrote in message
···················@free.fr...
> "Dragontamer" <··@dragontamer.is-a-geek.com> writes:
>
> > Hi, i am attempting to write a mud (in clisp), but i have stumbled
> >upon a problem.
> >
> > Muds require to accept multiple connections into one port (or so it
seems).
> > How do you do that?
> >
> > Thx in advance.
> >
> Hi,
>
> I've made this little test code under clisp.
> Maybe you can find it useful.
>
> ----------------------------------------------------------------------
> (defvar *all-clients* '())
> (defvar *port* 25555)
>
> (defun close-and-quit ()
>   (format t "End of connexion~%")
>   (dolist (client *all-clients*)
>     (close client))
>   (socket-server-close sock)
>   (quit))
>
> (defun client-quit (client)
>   (format t "client has quit : ~A~%" client)
>   (format client "Bye...~%")
>   (close client)
>   (setq *all-clients* (remove client *all-clients*)))
>
> (defun info-on-server (client)
>   (format client "There is ~A client connected to the server~%"
>   (length *all-clients*))
>   (format client "sockets = ~A~%" *all-clients*))
>
> (defun send-to-all (client str)
>   (format t "~A~%" str)
>   (dolist (cl *all-clients*)
>     (unless (eq client cl)
>       (when (nth-value 1 (ignore-errors (format cl "~A~%" str)))
> (client-quit cl)))))
>
> (defun read-command (client)
>   (let ((str (read-line client)))
>     (cond ((string-equal str "") nil)
>   ((string-equal str "quit") (client-quit client))
>   ((string-equal str "close") (close-and-quit))
>   ((string-equal str "info") (info-on-server client))
>   (t (send-to-all client str)))))
>
> (format t "Start serveur on port ~A~%" *port*)
> (setq sock (socket-server *port*))
>
> (loop
>  (when (socket-wait sock 0 1)
>    (let ((new-sock (socket-accept sock)))
>      (push new-sock *all-clients*)
>      (format t "New connexion: ~A~%" *all-clients*)
>      (format new-sock "Welcome! commands are quit/close/info
> Everything else is send to all clients.~%")))
>  (dolist (client *all-clients*)
>    (when (listen client)
>      (read-command client))))
> ----------------------------------------------------------------------
>
> -- 
> Philippe Brochard    <hocwp _CHEZ_ free.fr>
>                       http://hocwp.free.fr
From: Karl A. Krueger
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <buh2p0$mhr$1@baldur.whoi.edu>
Yang, Chul-woong <······@dbserver.kaist.ac.kr> wrote:
> I'm in same situation with dragontamer. (i'm lisp newbie)
> Philippe's answer is very helpful, thx.
> 
> Anyway, are there any simple network server example code with
> thread/process model in clisp/sbcl?
> (i.e. listen(), accept(), fork() or pthread_create() model in C.
> Phillipe's code seems to be listen(), accept() and select() model.)

This is an SBCL multithreaded TCP server implementation, along with an
example which just implements TCP echo.  It dispatches one background
thread for the server, which spawns more threads for the clients.

(Does anyone know why sb-bsd-sockets::inet-address-any isn't exported?)

;
; Threaded TCP servers ...
;

(require :sb-bsd-sockets)
(use-package :sb-thread)
(use-package :sb-bsd-sockets)
(use-package :sb-unix)

(defmacro handle-socket-errors (socket &body body)
  "Eat my socket when it fails."
  `(handler-case
        (progn ,@body)
      (end-of-file (condition)
          (socket-close ,socket)
          condition)
      (sb-bsd-sockets::socket-error (condition)
          (socket-close ,socket)
          condition)))

(let ((tcp (get-protocol-by-name "tcp")))
  (defun make-tcp-socket ()
    "Create a brand new TCP socket, good for all your TCP-ing needs."
    (make-instance 'inet-socket
                   :type :stream
                   :protocol tcp)))

(defmacro with-tcp-socket (sock &body body)
  "Guaranteed close on socket."
  `(let ((,sock (make-tcp-socket)))
     (unwind-protect
       (progn ,@body)
       (socket-close ,sock))))

(defun single-tcp-server (port handler)
  (declare (function handler))
  "One thread, one connection at a time."
  (with-tcp-socket sock
    (socket-bind sock sb-bsd-sockets::inet-address-any port)
    (socket-listen sock 10)
    (loop
      (multiple-value-bind (clientsocket peer) (socket-accept sock)
        (funcall handler clientsocket peer)))))

(defun make-handler-thread (sock handler peer)
  (declare (function handler))
  (let ((handler-call 
          (lambda () 
            (funcall handler sock peer))))
    (make-thread handler-call)))

(defun threaded-tcp-server (port handler)
  (declare (function handler))
  "All the connections you want."
  (with-tcp-socket sock
    (socket-bind sock sb-bsd-sockets::inet-address-any port)
    (socket-listen sock 10)
    (loop
      (multiple-value-bind (clientsocket peer) (socket-accept sock)
        (let ((thread (make-handler-thread clientsocket handler peer)))
          (format t "Thread ~A dispatched for ~A.~%" thread peer))))))

(defun spawn-tcp-server (port handler)
  (declare (function handler))
  "Background yourself a TCP server."
  (let ((server (lambda () (threaded-tcp-server port handler))))
    (let ((thread (make-thread server)))
      (format t "Server thread ~A started.~%" thread))))

(defun echoer (sock peer)
  "Socket handler that just echoes."
  (handle-socket-errors sock
    (let ((str (socket-make-stream sock :input t :output t :buffering :none)))
      (write-line (format nil "Hello ~A !~%" peer) str)
      (loop (write-line (read-line str) str)))))

(spawn-tcp-server 9123 #'echoer)


-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: Yang, Chul-woong
Subject: Re: Help, Multiple connections.. (sbcl & slime question)
Date: 
Message-ID: <cP3Pb.30368$T3.452735@news.bora.net>
Thanks! It works.

some question continues.

1) When I ran Karl's program in sbcl using 'load', there is no problem.
But to compile file... sbcl reports several errors "undefined function..."
It seems that require and use-package cmd does not works.
How to overcome this?
; in: LET ((TCP (GET-PROTOCOL-BY-NAME "tcp")))
;     (GET-PROTOCOL-BY-NAME "tcp")
;
; caught STYLE-WARNING:
;   undefined function: GET-PROTOCOL-BY-NAME
; in: DEFUN SPAWN-TCP-SERVER
;     (MAKE-THREAD SERVER)
;
; caught STYLE-WARNING:
;   undefined function: MAKE-THREAD


2) I use slime emacs mode.
when i issue M-x slime, it always reports following message.
(maybe slime always compiles slime related source. why?)
causing startup delays about 30 seconds (in compiling?)
though not critical, very annoying. can you see the reason?

; in: LAMBDA NIL
;     (FUNCALL (FIRST SWANK::ARGS))
; --> SB-C::%FUNCALL THE
; ==>
;   (SB-KERNEL:%COERCE-CALLABLE-TO-FUN FUNCTION)
;
; note: unable to
;         optimize away possible call to FDEFINITION at runtime
;       due to type uncertainty:
;         The first argument is a (OR FUNCTION SYMBOL), not a FUNCTION.
;
; note: unable to
;         optimize away possible call to FDEFINITION at runtime
;       due to type uncertainty:
;         The first argument is a (OR FUNCTION SYMBOL), not a FUNCTION.
;     (FUNCALL FUNCTION)
; --> SB-C::%FUNCALL THE
; ==>
;   (SB-KERNEL:%COERCE-CALLABLE-TO-FUN FUNCTION)
From: Christophe Rhodes
Subject: Re: Help, Multiple connections.. (sbcl & slime question)
Date: 
Message-ID: <sq7jzm3kul.fsf@lambda.dyndns.org>
"Yang, Chul-woong" <······@dbserver.kaist.ac.kr> writes:

> Thanks! It works.
>
> some question continues.
>
> 1) When I ran Karl's program in sbcl using 'load', there is no problem.
> But to compile file... sbcl reports several errors "undefined function..."
> It seems that require and use-package cmd does not works.
> How to overcome this?

> ; in: LET ((TCP (GET-PROTOCOL-BY-NAME "tcp")))
> ;     (GET-PROTOCOL-BY-NAME "tcp")
> ;
> ; caught STYLE-WARNING:
> ;   undefined function: GET-PROTOCOL-BY-NAME
> ; in: DEFUN SPAWN-TCP-SERVER
> ;     (MAKE-THREAD SERVER)
> ;
> ; caught STYLE-WARNING:
> ;   undefined function: MAKE-THREAD

The source code from the parent post has a number of forms at
top-level that do not have an effect at compile-time, among them
REQUIRE and USE-PACKAGE.  To request that they have compile-time
effect as well as load-time and execute time, they should be
wrapped in
  (eval-when (:compile-toplevel :load-toplevel :execute)
    (require :sb-bsd-sockets)
    (use-package ...)
    ...)
so that the environment for the compiler is the correct one.  (LOAD on
source processes the forms one-at-a-time, while the file compiler
processes the whole file before executing any of them, absent
EVAL-WHEN).

Alternatively, the environment could be set up before the compilation
stage, by ensuring that the modules and packages are loaded before
running COMPILE-FILE.

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Luke Gorrie
Subject: Re: Help, Multiple connections.. (sbcl & slime question)
Date: 
Message-ID: <lhektueuba.fsf@dodo.bluetail.com>
"Yang, Chul-woong" <······@dbserver.kaist.ac.kr> writes:

> 2) I use slime emacs mode.
> when i issue M-x slime, it always reports following message.
> (maybe slime always compiles slime related source. why?)
> causing startup delays about 30 seconds (in compiling?)
> though not critical, very annoying. can you see the reason?

SLIME automatically recompiles its Lisp code if the sources are newer
than the binaries, so you should only get this startup delay after you
update the code.

I'll look for a way to suppress the many efficiency-notes SBCL prints
while compiling the backend code.
From: Kenny Tilton
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <caUOb.229101$0P1.117076@twister.nyc.rr.com>
Yang, Chul-woong wrote:

> I'm in same situation with dragontamer. (i'm lisp newbie)

<pounce>
Tell us more!:

    http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey

</pounce>

kenny

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Karl A. Krueger
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <buh2u7$mhr$2@baldur.whoi.edu>
Kenny Tilton <·······@nyc.rr.com> wrote:
> <pounce>
> Tell us more!:
>    http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
> </pounce>

Is it just me, or are a lot of the responses missing ... ?

-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: Kenny Tilton
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <MHUOb.229241$0P1.211522@twister.nyc.rr.com>
Karl A. Krueger wrote:

> Kenny Tilton <·······@nyc.rr.com> wrote:
> 
>><pounce>
>>Tell us more!:
>>   http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
>></pounce>
> 
> 
> Is it just me, or are a lot of the responses missing ... ?
> 

Yes, you have to to the Highlight Film (see my sig) to see almost all 
(and I'll have to keep up with that as new Roads are added).

The cross-referencing mechanism seems broken, and I have not been able 
to attract any help with a couple of flares.

kenny

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Edi Weitz
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <m365f7akxd.fsf@bird.agharta.de>
On Mon, 19 Jan 2004 17:44:12 GMT, Kenny Tilton <·······@nyc.rr.com> wrote:

> The cross-referencing mechanism seems broken, and I have not been
> able to attract any help with a couple of flares.

There's a similar bug on CLiki - looks like it was introduced when the
code was updated some weeks ago. The problem seems to be that Dan
Barlow currently doesn't have Internet access so he can't fix it.

Cheers,
Edi.
From: Ivan Toshkov
Subject: Re: Help, Multiple connections using clisp sockets
Date: 
Message-ID: <buhig1$ht8qj$1@ID-207269.news.uni-berlin.de>
Edi Weitz wrote:
> On Mon, 19 Jan 2004 17:44:12 GMT, Kenny Tilton <·······@nyc.rr.com> wrote:
> 
> 
>>The cross-referencing mechanism seems broken, and I have not been
>>able to attract any help with a couple of flares.
> 
> 
> There's a similar bug on CLiki - looks like it was introduced when the
> code was updated some weeks ago. The problem seems to be that Dan
> Barlow currently doesn't have Internet access so he can't fix it.
> 
> Cheers,
> Edi.

Seems like Cliki keeps older versions of the pages from this release, 
but that brakes the cross-reference code.  E.g. the page <URL: 
http://www.cliki.net/Common%20Lisp%20implementation> mentions Movitz 6 
times, wich is exactly the number of versions of the Movitz page.

This is a still a guess, though, 'cause I haven't checked the code.

--
Ivan Toshkov

··········@last-name.org