On 01.11.10 23:51, Jeff Rogers wrote:
It looks like my previous answer was, at best, partially
right. It looks lke [ns_conn channel] does in fact give
you a read/write channel. The effect of the missing
content-length header is to discard any data that was read
past the headers. Attached is a patch (readahead.patch)
to change that behavior. The patch does 2 things: one,
if the request includes 'upgrade' in the connection
header, it doesn't read past the header (and doesn't throw
away what it has read). Two, when [ns_conn channel] is
called, it will insert into the channel buffer any data
that was already read (and not processed) on the socket.
Combined, it means that on an upgrade connection you can
get the entire body, even if there was no content-length
header sent.
nice!
Importantly, this design of thread-per-connection is not
scalable - your server will fall down and start crying
once you start up a few dozen threads. (perhaps more; a
really rough guess is that each tcl thread consumes 2M of
memory before doing anything). What you really want to do
is to transfer each new websocket to a single existing
background thread, but I'm not sure how to send stuff into
another thread's event loop using the aolserver thread tools.
The standard tcl thread package is more powerful (with
thread::send and thread::wait) but I don't know if those
play nice inside AOLserver.
the bgdelivery-procs in the OpenACS CVS [1] do exactly this
(using tcl threads and native tcl streams)
We use bgdelivery in production since several years, with up to
a mio bgdeliveries per day, so i can assert, this runs
stable and
scalable (in aolserver 4.0, 4.5 and naviserver). Often, we see
more than 100 concurrent deliveries running, just occupying a
single thread.
Here is a significantly simplified example showing the guts:
- get channel
- transfer channel
- send thread a command to continue work using the open channel
proc spool_jpeg {jpeg_file} {
if {[ns_headers 200 image/jpeg [file size
$jpeg_file]]} {
set chan [ns_conn channel]
thread::transfer $::serverThreadId $chan
thread::send -async $::serverThreadId [list
spoolfile -channel $chan -file $jpeg_file]
}
}
The bgdelivery-procs [1] do more than only delivering plain
files (FileSpool), so they do more than one needs for e.g.
websockets. The gb-delivery-procs handle as well
h264 pseudo streaming and http spooling, and provide as
well a publish-subscriber handling for broadcasting info to
multiple subscribers in a comet-style (web clients keep a
connection open, therefore web-clients for e.g. a chat
work immediately without polling).
One important advantage of the tcl thread package is that it
is sitting
in an event loop, so it is easy to communicate to it from
all other
threads in a sync or async fashion. The reason for using
tcl streams instead of ns_streams is that in some situations
one simply needs it since the existing interfaces require it
(unless
reprogramming certain modules based on aolserver streams). One
such use case is the tcl command fcopy, which is used by
bgdelivery.
One important disadvantage of using native tcl streams is
that once
you are working on the native tcl streams, ns_stream
functionality
is gone. So, if one connects via https, the native tcl
stream can't
decode the content (this requires running a reverse proxy such
as nginx in such situations, which is for larger sites
anyhow a good idea). One can use https + bgdelivery via
tcl's tls
package nicely for e.g. outgoing connections.
best regards
-gustaf neumann
[1]
http://cvs.openacs.org/browse/OpenACS/openacs-4/packages/xotcl-core/tcl/bgdelivery-procs.tcl?r=HEAD
--
AOLserver - http://www.aolserver.com/
To Remove yourself from this list, simply send an email to
<[email protected]> with the
body of "SIGNOFF AOLSERVER" in the email message. You can leave the Subject:
field of your email blank.