As title. I want to write something to read strings from a socket
stream without a timeout value.
But I cannot find anything similar as the "select" function in BSD
socket. So I now can only get the thing done like this:
(loop do
(setq c (read-char-no-hang s))
...
(if (or (get-the-result-we-want?)
(time-out?))
(return))
(sleep 0.25)))
It is not good and wastes the CPU time.
When we use BSD socket (in C), we can do something like this:
FD_ZERO(&fdset);
FD_SET(sockfd, &fdset);
select(0, &fdset, NULL, NULL, &timeout);
How can we do the same thing in common lisp?
BJ> As title. I want to write something to read strings from a socket
BJ> stream without a timeout value.
BJ> But I cannot find anything similar as the "select" function in BSD
BJ> socket. So I now can only get the thing done like this:
there's no portable thing, but you can have it implementation-specific.
BJ> When we use BSD socket (in C), we can do something like this:
BJ> FD_ZERO(&fdset);
BJ> FD_SET(sockfd, &fdset);
BJ> select(0, &fdset, NULL, NULL, &timeout);
BJ> How can we do the same thing in common lisp?
i guess you can have such functionality with mp:with-timeout in lisps which
support multiprocessing
Brian Jiang <········@gmail.com> wrote:
+---------------
| As title. I want to write something to read strings from a socket
| stream without a timeout value.
+---------------
I assume you meant "WITH a timeout value"...
+---------------
| But I cannot find anything similar as the "select" function
| in BSD socket.
+---------------
It's not part of the ANSI CL Standard, no, but most CLs that run
on Unix/Linux/Posix platforms provide either explicit or implicit
use of "select()" or "poll()" or equivalents.
For example, in CMUCL *all* I/O is done using "select()" deep under
the covers, which makes it very easy to write multi-threaded servers
that don't hang when one of the threads does a "blocking" read, even
though CMUCLs "processes" are really only cooperatively-scheduled
green threads within a single Unix process.
This interface is exposed to the user in several places, but
probably the most useful to you would be the thread utility
MP:PROCESS-WAIT-UNTIL-FD-USABLE, which you might use in this
style [note that floating-point timeouts are also supported,
e.g., 2.5 s, say]:
> (defun read-line-with-timeout (stream timeout timeout-value eof-value)
(let ((fd (system:fd-stream-fd stream)))
(if (mp:process-wait-until-fd-usable fd :input timeout)
(read-line stream nil eof-value)
timeout-value)))
READ-LINE-WITH-TIMEOUT
> (read-line-with-timeout system:*stdin* 10 :got-timout :got-eof)
heloo there!
"heloo there!"
NIL
> (read-line-with-timeout system:*stdin* 10 :got-timout :got-eof)
^D
:GOT-EOF
T
> (read-line-with-timeout system:*stdin* 10 :got-timout :got-eof)
:GOT-TIMOUT
>
I just waited for 10 seconds without typing anything in the last case.
Other CL implementations probably supply some equivalent functionality...
-Rob
p.s. If you're reading data without line terminations, you'll need
to do something a little more complicated. In CMUCL, take a look
at the extension SYSTEM:MAKE-FD-STREAM, which allows you to set
both buffering style and timeout values on an FD-STREAM (which
socket streams are).
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Thanks a lot for your replies and they are very useful for me.
Yes, I mean "WITH a timeout" and sorry for the typo.
And I dig the documents of the four lisp implementations installed in
my computer further and here are examples how I now set a timeout for
the socket stream.
#+sbcl
(sb-sys:wait-until-fd-usable (sb-sys:fd-stream-fd stream)
:input timeout)
#+:clisp
(socket:socket-status (cons stream :input) timeout)
#+:allegro
(sys:with-timeout (timeout (print "timeout allegro")
(setq ret nil))
(setq ret (peek-char nil stream nil :eof))
))
#+:lispworks
(setf (stream:stream-read-timeout sock-stream) timeout)
;; then when (read-char stream nil :eof) timout, it returns :eof.
;; To distinguish it is a real eof or just timeout, I have to do
something like
;; this:
(setq c (read-char-no-hang sock-stream nil :eof))
(cond ((NULL c)
;; Not eof. just no data available now
)
((eq c :eof)
;; real eof
(setf eof t))
(t
;; not likely the codes can fall down here.
)))
;; Maybe there is a better way.
> When we use BSD socket (in C), we can do something like this:
> FD_ZERO(&fdset);
> FD_SET(sockfd, &fdset);
> select(0, &fdset, NULL, NULL, &timeout);
>
> How can we do the same thing in common lisp?
check out iolib, it gives you portable access to the BSD sockets
(among other things): http://common-lisp.net/project/iolib/
- attila
From: Magnus Henoch
Subject: Re: Is there something like "select" function for socket in common lisp library?
Date:
Message-ID: <87d4tymlvi.fsf@dtek.chalmers.se>
Would cl-event help? http://www.cliki.net/cl-event
Magnus