From ... From: Erik Naggum Subject: Re: Newbie Q. How do I use sockets? Date: 2000/06/28 Message-ID: <3171189497310759@naggum.no>#1/1 X-Deja-AN: 639996539 References: <3957E5B0.706448C4@spam.com> mail-copies-to: never Content-Type: text/plain; charset=us-ascii X-Complaints-To: newsmaster@eunet.no X-Trace: oslo-nntp.eunet.no 962202527 28220 195.0.192.66 (28 Jun 2000 14:28:47 GMT) Organization: Naggum Software; vox: +47 8800 8879; fax: +47 8800 8601; http://www.naggum.no User-Agent: Gnus/5.0803 (Gnus v5.8.3) Emacs/20.7 Mime-Version: 1.0 NNTP-Posting-Date: 28 Jun 2000 14:28:47 GMT Newsgroups: comp.lang.lisp * Richard James Panturis Giuly | How do I access tcp sockets with lisp? There's a lot of stuff you can do, and then you can avoid most of the problems with a few simple macros: (defmacro with-network-server ((variable &key keep-open (host 0) port log-error options) &body body) "Set up a simple network server. The server socket is opened on HOST:PORT, default *:PORT if no HOST is specified. Further socket options may be supplied as a list of keyword-value pairs in OPTIONS. The BODY is executed with VARIABLE (a symbol) bound to each incoming connection, which is gauranteed to be closed upon exit from BODY unless KEEP-OPEN is true. If a socket error occurs during socket creation, it is logged as a critical error (unless LOG-ERROR is false) and the error is re-signaled. If not caught elsewhere, this form returns the error object. An error when accepting a connection is ignored. Errors in the body invoke the debugger for now, as do non-socket errors elsewhere." (let ((server (gensym))) `(let ((,server (handler-case (make-socket :connect :passive :local-host ,host :local-port ,port ,@options) (socket-error (error) (case (socket-error-code error) ((:address-in-use :address-not-available) (signal error) error) (t ,(when log-error `(write-system-log :critical "Could not create server on ~A:~D:~%~A" ,host ,port error)) (signal error) error)))))) (if (typep ,server 'socket) (unwind-protect (loop (let ((,variable (accept-connection ,server))) ,(if keep-open `(when (typep ,variable 'socket) ,@body) `(when (typep ,variable 'socket) (unwind-protect (progn ,@body) (when (typep ,variable 'socket) (close ,variable))))))) (when (typep ,server 'socket) (close ,server))) ,server)))) (defmacro with-network-client ((variable &key keep-open (host 0) port log-error options) &body body) "Set up a simple network client. The client socket is opened to HOST:PORT, default :PORT if no host is specified and bound to VARIABLE across BODY, to be closed on exist, unless kEEP-OPEN is true. If a socket error occurs during socket creation, it is logged as a notice (unless LOG-ERROR is false) and the error is re-signaled. If not caught elsewhere, this form returns the error object." `(let ((,variable (handler-case (make-socket :connect :active :remote-host ,host :remote-port ,port ,@options) (socket-error (error) (case (socket-error-code error) ((:network-down :network-unreachable :network-reset :host-down :host-unreachable) (signal error) error) ((:connection-timed-out :connection-refused) nil) (t ,(when log-error `(write-system-log :notice "Could not open connection to ~A:~D:~%~A" ,host ,port error)) (signal error) error)))))) ,(if keep-open `(if (typep ,variable 'socket) (progn ,@body) ,variable) `(if (typep ,variable 'socket) (unwind-protect (progn ,@body) (when (typep ,variable 'socket) (close, variable))) ,variable)))) Let's ignore the write-system-log call for now. I have a slightly modified version to obey the TELNET protocol, but it's too much to post here. The whois client goes like this: Example: (with-telnet-client (whois :host "whois.internic.net" :port "whois") (write-line "clemacs.org" whois) ;Automatic CRLF and force-output (ignore-errors (loop (write-line (read-line whois)))) (values)) #:Erik -- If this is not what you expected, please alter your expectations.