From: David Reitter
Subject: read-sequence from socket
Date: 
Message-ID: <eaa66a27-a2c2-47c7-b601-7ad85b079356@p31g2000prf.googlegroups.com>
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.)

From: Thomas A. Russ
Subject: Re: read-sequence from socket
Date: 
Message-ID: <ymimygeucqk.fsf@blackcat.isi.edu>
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
From: Rob Warnock
Subject: Re: read-sequence from socket
Date: 
Message-ID: <x46dnSe5f8AtlYzUnZ2dnUVZ_q7inZ2d@speakeasy.net>
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
From: Volkan YAZICI
Subject: Re: read-sequence from socket
Date: 
Message-ID: <8d1f930e-cff8-4bb2-93ba-b9b97527e9b5@q30g2000prq.googlegroups.com>
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/
From: Rob Warnock
Subject: Re: read-sequence from socket
Date: 
Message-ID: <HJydnT0Au7jnFYzUnZ2dnUVZ_ojinZ2d@speakeasy.net>
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
From: Duane Rettig
Subject: Re: read-sequence from socket
Date: 
Message-ID: <o03ai6fvs3.fsf@gemini.franz.com>
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