Hi all
I'm having some trouble with connection timeouts.
I'm writing an AJAX application where I need to push values from the server to the client at random times (it's a chat application.)
To avoid polling the server every second, I wrote it like this, to exploit hanging connections: - the client opens a connection with XMLHttpRequest - the server doesn't respond (the handler waits on a condition variable), keeping the connection hanging - when the server has data to send (new lines of chat) it does so, and: - the client receives the data, closes the connection and starts over - if the connection timeouts (on either end), the client starts over
This method worked beautifully on SBCL + TBNL + mod_lisp2 + Apache2, on any browser. It gave me the lowest possible lag (equal to the network latency) with very little network overhead.
Now on SBCL 0.9.17 + Hunchentoot 0.4.9 I'm having trouble with the Opera browser (and possibly others: I've only tested it on Opera and Firefox.)
By the way, Firefox doesn't seem to have any connection timeout: I've seen it receive a response after a (sleep 1800), without any packet sent by either side in half an hour!
Anyway I've used a sniffer to understand what's going on. Usually, when the connection times out client-side, these packets are exchanged:
C -> S ACK FIN ( C <- S ACK ) C <- S ACK FIN C -> S ACK
This way both sides agree that the connection is over.
But on SBCL + Hunchentoot vs. Opera, after 2 minutes the client times out and I see the following exchange:
C -> S ACK FIN C <- S ACK
I can't make sense of it: why does the server acknowledge the FIN packet but fail to send its own?
As a result the client thinks it's almost over... enough not to accept any data from the same connection again, but not enough to stop spinning and fire the XMLHttpRequest callback (which would open a new connection.)
Even worse, the server thinks it's still open, so it will send any new data on that wire. But the data won't be accepted by the client, which will send a RST as soon as it sees stuff coming from a 'dead' connection.
Help!
Toby
PS: All these tests were done with :read-timeout nil Maybe I should set it to 119 and forget about it :-)
On Thu, 16 Nov 2006 23:34:17 +0100, Toby tobia.conforto@linux.it wrote:
I'm having some trouble with connection timeouts.
I'm writing an AJAX application where I need to push values from the server to the client at random times (it's a chat application.)
To avoid polling the server every second, I wrote it like this, to exploit hanging connections:
- the client opens a connection with XMLHttpRequest
- the server doesn't respond (the handler waits on a condition variable), keeping the connection hanging
- when the server has data to send (new lines of chat) it does so, and:
- the client receives the data, closes the connection and starts over
- if the connection timeouts (on either end), the client starts over
This method worked beautifully on SBCL + TBNL + mod_lisp2 + Apache2, on any browser. It gave me the lowest possible lag (equal to the network latency) with very little network overhead.
Now on SBCL 0.9.17 + Hunchentoot 0.4.9 I'm having trouble with the Opera browser (and possibly others: I've only tested it on Opera and Firefox.)
By the way, Firefox doesn't seem to have any connection timeout: I've seen it receive a response after a (sleep 1800), without any packet sent by either side in half an hour!
Anyway I've used a sniffer to understand what's going on. Usually, when the connection times out client-side, these packets are exchanged:
C -> S ACK FIN ( C <- S ACK ) C <- S ACK FIN C -> S ACK
This way both sides agree that the connection is over.
But on SBCL + Hunchentoot vs. Opera, after 2 minutes the client times out and I see the following exchange:
C -> S ACK FIN C <- S ACK
I can't make sense of it: why does the server acknowledge the FIN packet but fail to send its own?
As a result the client thinks it's almost over... enough not to accept any data from the same connection again, but not enough to stop spinning and fire the XMLHttpRequest callback (which would open a new connection.)
Even worse, the server thinks it's still open, so it will send any new data on that wire. But the data won't be accepted by the client, which will send a RST as soon as it sees stuff coming from a 'dead' connection.
I'm afraid I can't help you here - it /looks/ like something that happens on a level below Hunchentoot. One thing you could test is if this happens with AllegroCL or LispWorks as well. (CMUCL is probably not a good target as it might be too similar to SBCL.)
If it doesn't happen, I'd suggest taken this to the SBCL mailing list. If it does, feel free to ask here again although I at least still wouldn't have an answer...
PS: All these tests were done with :read-timeout nil Maybe I should set it to 119 and forget about it :-)
Have you tried (with a short timeout)? Does it make a difference?
Edi Weitz wrote:
PS: All these tests were done with :read-timeout nil Maybe I should set it to 119 and forget about it
Have you tried (with a short timeout)? Does it make a difference?
Actually, when the client timeout happens the worker thread is waiting on a condition variable, not on a socket read, so :read-timeout doesn't have anything to do with my problem.
Instead, timing out of my condition variable after less than 2 minutes and telling the client to start a new request does work, although it's not an ideal solution (as some browsers could have a shorter timeout.)
One thing you could test is if this happens with AllegroCL
I just made some tests with Hunchentoot on AllegroCL, AllegroServe on AllegroCL and even PHP5 on Apache! To my surprise, they all behave like Hunchentoot on SBCL! Apparently what I considered the "right behaviour" was a quirk in the mod_lisp2 setup I was using before.
I guess I need to dust some socket programming textbook!
Toby