#| SOCKETTHREADS.LISP Simple examples of sockets and threads in ABCL Common LISP. Clark Elliott 2019-05-19 See how to run, and example output at the bottom of the file. |# (setf GameAddr 8894) (defvar GameStream nil) (defvar GameSocket nil) (defun Connect2Game () (let ((GameSocket (make-socket "localhost" GameAddr))) (setf GameStream (get-socket-stream GameSocket)))) (defun CloseGame () (close GameStream) (socket-close GameSocket) (server-socket-close GameServerSocket)) (defun Gameclient () (let ((s nil)) (format t "Type in what you want to send to the Game:~%~%") (dotimes (n 5) (setf s (read-line)) (format GameStream "~s~%" s)) (format t "From the server:~%~s~%" (read-line GameStream)) )) ;;; This Server works (defun GameServer () (let ((s (make-server-socket GameAddr)) (val nil) (n 0) (b nil)) (setq GameServerSocket s) ; so I can close it later if crash (setq GameSocket (socket-accept s)) (setf GameStream (get-socket-stream GameSocket)) (setf ww GameStream) (format t "About to read a line~%") (setf val (read-line GameStream)) ; Block waiting (format t "~a~%" val) (loop while (< (incf n) 5) do (setf val (read-line GameStream)) (format t "Got: ~a~%" val)) (format GameStream "THANK YOU FOR YOUR COMMENTS~%") (server-socket-close s))) ;;; This closure works as well, but be careful about standard output, esp. with SLIME. (let ((closure-game nil)) (defun make-it () (setf closure-game (threads:make-thread #'(lambda () (let ((s (make-server-socket GameAddr)) (val nil) (n 0) (b nil)) (format t "I am alive!~%") (setq GameServerSocket s) ; so I can close it later if crash (setq GameSocket (socket-accept s)) (setf GameStream (get-socket-stream GameSocket)) (setf ww GameStream) (format *standard-output* "About to read a line~%") (setf val (read-line GameStream)) ; Block waiting (format t "~a~%" val) (loop while (< (incf n) 5) do (setf val (read-line GameStream)) (format t "Got: ~a~%" val)) (format GameStream "THANK YOU FOR YOUR COMMENTS~%") (server-socket-close s) (format *standard-output* "Goodbye Cruel World~%")))))) ;; Works, but takes a while: (defun kill-it () (threads:destroy-thread closure-game)) (defun alivep () (THREADS:THREAD-ALIVE-P closure-game)) ) (defun close-em () (close ww) (socket-close ax) (server-socket-close nn)) (setf my-val 1) ;;; Output to *standard-output* for Inferior Lisp, so careful with SLIME: (defun make-a-thread () (setf q (threads:make-thread #'(lambda () (format t "I am alive!~%") (sleep 15) (format t "Goodbye Cruel World~%") (setf my-val (1+ my-val)))))) ;;; Works, but takes a while: (defun kill-it () (threads:destroy-thread q)) (defun alivep () (THREADS:THREAD-ALIVE-P q)) #| Example of running the simple game conversation between client and server, run in two separate command windows: On the SERVER: CL-USER(2): (gameserver) About to read a line "one" Got: "two" Got: "three" Got: "four" Got: "five" T CL-USER(3): On the CLIENT: CL-USER(2): (connect2game) # CL-USER(3): (gameclient) Type in what you want to send to the Game: one two three four five From the server: "THANK YOU FOR YOUR COMMENTS" NIL CL-USER(4): ----------------------------------------------- The background server: CL-USER(4): (make-it) # CL-USER(5): I am alive! About to read a line "This is line one to the background server" Got: "two" Got: "three" Got: "four" Got: "five" Goodbye Cruel World ----------------------------------------------- The client for the background server (same as before): CL-USER(6): (connect2game) # CL-USER(7): (gameclient) Type in what you want to send to the Game: This is line one to the background server two three four five From the server: "THANK YOU FOR YOUR COMMENTS" NIL CL-USER(8): ----------------------------------------------- The sample thread running in the background: my-val 2 CL-USER(8): (make-a-thread) # CL-USER(9): I am alive! Goodbye Cruel World my-val 3 CL-USER(10): Sample output: CL-USER(12): (make-a-thread) # CL-USER(13): I am alive! (kill-it) T CL-USER(14): (alivep) NIL CL-USER(15): (make-a-thread) # CL-USER(16): I am alive! (alivep) T CL-USER(17): Goodbye Cruel World (alivep) NIL CL-USER(18): CL-USER(18): (make-a-thread) # CL-USER(19): I am alive! (alivep) T CL-USER(20): (kill-it) T CL-USER(21): (alivep) NIL CL-USER(22): --------------------------- |#