Subject: Re: Newbie Q. How do I use sockets? From: Erik Naggum <erik@naggum.no> Date: 2000/06/28 Newsgroups: comp.lang.lisp Message-ID: <3171189497310759@naggum.no> * Richard James Panturis Giuly <no@spam.com> | 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 <localhost>: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.