I'm trying to read into a buffer from a socket using `read-sequence'.
I'd like `read-sequence' to stop when there is no more data, and
the :input-timeout argument to `make-socket' in the current CCL allows
me to specify a timeout, upon which an error is signalled. However,
I'm unclear how I would then find out how many bytes were read -
that's the normal return value of `read-sequence'.
(let ((*data* (make-array 1000 :initial-element nil))))
(handler-case
(read-sequence *data* conn)
(input-timeout (ee) nil)))
I could not find any documentation of the error object that I am
getting with this `input-timeout' error.
Any help appreciated. (Emacs Lisp hacker, but CL novice.)
David Reitter <·············@gmail.com> writes:
> I'm trying to read into a buffer from a socket using `read-sequence'.
>
> I'd like `read-sequence' to stop when there is no more data, and
> the :input-timeout argument to `make-socket' in the current CCL allows
> me to specify a timeout, upon which an error is signalled. However,
> I'm unclear how I would then find out how many bytes were read -
> that's the normal return value of `read-sequence'.
http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_seq.htm
Now, what isn't clear, is whether read-sequence is allowed to return
less than the full buffer (say, from an interactive or network stream)
if it DOESN'T get an end-of-file. The documentation hints that it might
need to always fill the buffer unless it encounters end-of-file, but it
doesn't come right out and really clearly say that. I guess it is
implied, but it would have been nice to have a clearer statement.
> I could not find any documentation of the error object that I am
> getting with this `input-timeout' error.
This would be implementation dependent, since sockets and network I/O
are not part of the standard. You would need to see what CCL's
documentation says about it. IIRC, the sockets work a bit differently
than the older MCL sockets.
--
Thomas A. Russ, USC/Information Sciences Institute
David Reitter <·············@gmail.com> wrote:
+---------------
| I'm trying to read into a buffer from a socket using `read-sequence'.
|
| I'd like `read-sequence' to stop when there is no more data, and
| the :input-timeout argument to `make-socket' in the current CCL allows
| me to specify a timeout, upon which an error is signalled. However,
| I'm unclear how I would then find out how many bytes were read -
| that's the normal return value of `read-sequence'.
+---------------
You're going to find that doing this with READ-SEQUENCE is likely
to interact badly with the underlying operating system, since if
the timeout exception occurs in the middle of a read the "amount
already read" is not well-defined for many [most?] OSs.
What I would do instead in this case is write your own version
of READ-SEQUENCE which uses whatever underlying "select()/poll()"
calls [or equiv.] intermingled with native "read()"s (which will
be non-blocking if you only issue one when the "select()/poll()"
says there's something there [though if you're really paranoid
you might want to do an FIONREAD "ioctl()" or equiv. to be sure]),
so that the timeouts *only* ever occur during the "select()/poll()"
calls. In that case, you'll have a deterministic count of "amount
already read".
-Rob
p.s. Even with the above, setting a static timeout value which
can properly handle unexpected delays [e.g. temporary routing
loops or route flapping] which can persist for several minutes
is considered by networking experts to be... "interesting", at
the very least. You have been warned. ;-}
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
On Nov 5, 4:45 am, ····@rpw3.org (Rob Warnock) wrote:
> What I would do instead in this case is write your own version
> of READ-SEQUENCE which uses whatever underlying "select()/poll()"
> calls [or equiv.] intermingled with native "read()"s (which will
> be non-blocking if you only issue one when the "select()/poll()"
> says there's something there [though if you're really paranoid
> you might want to do an FIONREAD "ioctl()" or equiv. to be sure]),
> so that the timeouts *only* ever occur during the "select()/poll()"
> calls. In that case, you'll have a deterministic count of "amount
> already read".
How about using WAIT-FOR-INPUT with a TIMEOUT value in USOCKET[1]?
Moreover, as a bonus, you get compatibility availability between
different Common Lisp implementations.
Regards.
[1] http://common-lisp.net/project/usocket/
Volkan YAZICI <·············@gmail.com> wrote:
+---------------
| On Nov 5, 4:45 am, ····@rpw3.org (Rob Warnock) wrote:
| > What I would do instead in this case is write your own version
| > of READ-SEQUENCE which uses whatever underlying "select()/poll()"
| > calls [or equiv.] intermingled with native "read()"s (which will
| > be non-blocking if you only issue one when the "select()/poll()"
| > says there's something there [though if you're really paranoid
| > you might want to do an FIONREAD "ioctl()" or equiv. to be sure]),
| > so that the timeouts *only* ever occur during the "select()/poll()"
| > calls. In that case, you'll have a deterministic count of "amount
| > already read".
|
| How about using WAIT-FOR-INPUT with a TIMEOUT value in USOCKET[1]?
| [1] http://common-lisp.net/project/usocket/
+---------------
Uh... AFAICT that just gives you a "select()/poll()" with timeout
[which is how (WAIT-FOR-INPUT ... :TIMEOUT ...) is likely to be
implemented in current OSs], exactly as I suggested above.
You still need to do a non-blocking read and then wrap a loop
around pairs of "WAIT-FOR-INPUT"s & read"s to effect the full
semantics of READ-SEQUENCE. [AFACT USOCKET doesn't support a
:TIMEOUT arg to READ-SEQUENCE. But see Duane Rettig's parallel
reply re the extensions Allegro has to READ-SEQUENCE...]
+---------------
| Moreover, as a bonus, you get compatibility availability between
| different Common Lisp implementations.
+---------------
Well, those that support USOCKET... ;-}
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
David Reitter <·············@gmail.com> writes:
> I'm trying to read into a buffer from a socket using `read-sequence'.
>
> I'd like `read-sequence' to stop when there is no more data, and
> the :input-timeout argument to `make-socket' in the current CCL allows
> me to specify a timeout, upon which an error is signalled. However,
> I'm unclear how I would then find out how many bytes were read -
> that's the normal return value of `read-sequence'.
>
> (let ((*data* (make-array 1000 :initial-element nil))))
>
> (handler-case
> (read-sequence *data* conn)
> (input-timeout (ee) nil)))
>
> I could not find any documentation of the error object that I am
> getting with this `input-timeout' error.
>
> Any help appreciated. (Emacs Lisp hacker, but CL novice.)
Allegro CL adds a :partial-fill keyword to read-sequence, which causes
it to perform the way it probably should have been spoecified (see
http://www.franz.com/support/documentation/8.1/doc/streams.htm#cl-funs-2
for the implementation-specific notes on read-sequence). However, the
return value is a little hard to use (at least it is more complicated
than returning a simple count) and it is inconsistent with the return
value of write-sequence, which also perhaps should have been specified
to not block. This argument was only added to read-sequence to allow
for some level of compatibility between past implementations of
read-sequence, which had a split-personality - blocking was not done
when the stream was a socket, which was clearly not conformant, so we
changed the behavior to always fill-or-block and then provided a
backward-compatibility that allowed the older behavior to be specified
anyway.
When we implemented simple-streams many years ago, we decided to move
away from the tedious design of read-sequence/write-sequence, and we
created read-vector/write-vector (specified in
http://www.franz.com/support/documentation/8.1/doc/operators/excl/read-vector.htm
and
http://www.franz.com/support/documentation/8.1/doc/operators/excl/write-vector.htm)
which allowed us to make the interface look a lot more like the kinds
of reads and writes most operating systems provide. It also has the
added benefit of allowing byte-swapping specifications at the lowest
level, making automatc byte-swapping extremely efficient. The
blocking behavior of read-vector is also much more like that of
underlying operating systems; the first element is blocked on until
read, but any elements after the first will not be blocked on; if no
more data is ready the read-vector returns, and it always indicates
the actual number of bytes read.
--
Duane Rettig ·····@franz.com Franz Inc. http://www.franz.com/
555 12th St., Suite 1450, Oakland, Ca. 94607