Advanced Search
Welcome to Omgili,
Omgili (Oh My God I Love It ;) is a search engine for discussions. With Omgili you can find answers and solutions, debates, discussions, personal experiences, opinions and more... To learn more about Omgili click here.

This is a complete preview of the discussion as it was indexed by Omgili crawlers. Use this preview if the original discussion is unavailable.
Click here to view the original discussion.

IE Browser doesn't recognice when socket is closed ... - UNIX Socket FAQ

Hi, I am writing a small http-server as communication layer for my web applications (forum, BBG and so on).

Until now I had a HTTP/1.0 compliant server, but as I started to rewrite the whole system I thought it would be nice to upgrade to HTTP/1.1 and support persistent connections. Basically all works fine with browsers like Netscape, Mozilla 4/5, Opera 6/7 and even Konquerer in its past several versions.

However, it is costumary to timeout persistent connections after a while, usually after 10 to 20 seconds.

As said before, all browsers I testet but IE 5.5 and 6 have no problems with that.

Now, I do my shutdowns before the close, I tried it with SO_LINGER enabled at different values, I tried it without.

It's always the same. It's like this.

IE opens a connection and loads the data.

I timeout the still persistent connection after said 20 seconds.

If I click another link in the IE window (especially) right after the timeout it comes up with a "server not found" error message.

Now I wonder if there is a way I can make those IE thingies see the light like all others do?? Currently I use this close Code: void myclose(int socket) { char temp[500];

If(shutdown(socket, SHUT_WR)==0) while( read(socket,temp,500)>0);

Shutdown(socket,SHUT_RD);

Close(socket); } In parallel to this I tried several settings/combinations with SO_KEEPALIVE and SO_LINGER but it didn't help.

BTW, the close finishes its work and returns. The only way around the whole mess is to set the keep-alive value for the persistent connection to a value greater than the 60 seconds the IE keeps his side open, so that the IE closes his socket first.

But really, to keep an idle connection 61 seconds open is no option once you want to process several users at a time, it's not that there are limitless numbers of sockets, beside all the other wasted resources. I am currently running a SuSE Linux 8.1 So, any ideas what else I can try?

I've been googling for the past several days and I've read a lot, but basically all I've seen is that my shutdown/close should already be enough, even without additional linger enabled.

I am a bit lost now.

:(

Well, one solution would be to recognize that it was an IE browser, and simply fall-back to HTTP 1.0, and just disallow persistent connections for them...

I seem to recall Apache's config files do the same exact thing for some older versions of IE, but I thought that more recent versions had gotten things right...

Have you looked at the Apache source (or, any other HTTP server source), to see how they handle socket shutdown/closing?

I, personally, don't see anything too wrong with your posted method (aside from the fact that the while(read()) loop you've got there could potentially block forever, if the client never closes its end), but perhaps there is some special trickery required for dealing with wacky browsers... As an aside, have you tried a simple close(), without the shutdown() stuff, at all??

-cough- I allow persitent connections with HTTP/1.0 as long as they are made according to the rfc.

So a simple fall back wouldn't help that much. I could of course force a close for IEs, but as those are the mostly used our days it would certainly beat the purpose of the change to 1.1.

I found one bug in my code sofar.

I force kill child processes after a timeout (timeout can be set by the child any time) and I used to set it to a suicide value (1 sec) right before ending the connection.

Together with SO_LINGER set to 3 secs and a suicide value of 5 secs the IE now gets the end correct most of the times as long as no load operation starts within 0.5 secs or so after I actually closed the socket.

But then out of the blue it happens again, even after 30 or more seconds after the timeout.

IE is a mess. But I use not patched versions of IE, perhaps it's better with current versions...

The "child suicide" is a leftover from before kernel 2.2 days that sometimes kept the sockets forever in a fin_wait.

The hard kill was the only thing that freed the child process from waiting forever in the close. I've taken a look at the Apache 2 code, but they encapsulate the os specific stuff now in a way that it's nearly impossible to work through their low level stuff in a useful way. And no, the while(read()) loop is not endless.

Read doesn't block and returns with a value of 0 (no data) or a value of -1 (not connected or other error) in case there is nothing in the buffer.

;) Actually the Apache server uses something similar as a replacement for people whose machines have trouble using the SO_LINGER socket option. You basically have to shutdown a socket, close only eliminates your connection to it, it might exist happily ever after if it doesn't get a low level close (that's the shutdown for both, reading and writing) and if the client doesn't send a final fin.

Without shutdown the connected client can actually continue to write to it without even knowing that there isn't an application behind it anymore.

It is basically true that a process that exits will make the OS do most of the stuff, but it needs a lot longer, so the normal tcp implementations will let the socket linger for 1(Linux kernel 2.4)-4(current tcp standard) minutes in this case.

Older OS, for example Linux before kernel 2.2 let the socket hang around until reboot.

Not to forget again, that while the socket lingers, the child process just won't die.

So, if you are not absolutly sure that the connected process closes its side too, make a shutdown. Besides, in case of HTTP/1.1 you have to make a shutdown for reading if you won't accept incoming pilelined requests or if you plan to close a persistent connection after the current request to prevent the client from happily sending on its next request.

In case it intrests anybody, that would be what the mozilla guys seem to understand under pipelining, sending the next request while the answer of the current one is still not finished. So, let me explain what myclose does. -The shutdown(SHUT_WR) should flush the write buffer if there is any unsend data left and should send a fin right after that. -Then I clear the receive buffer with the while(read()) thingy, as the socket otherwise won't accept an incoming fin from the client. -Then I close the socket what should take care of the rest. But I will try nonth the less what happens if I don't shutdown the WR part prior to leaving the task or if I shut it down after the read part is finished.

Perhaps that helps...

I'm not sure what you're talking about with the shutdown() being 'required' in any way...

Just a close() will do the same work as a shutdown(SHUT_RDWR), assuming it's the last copy of the socket FD still open...

And, the whole point of SO_LINGER is to block your close() until all of the queued data is successfully sent... I never have much call to use it, myself;

If you don't use it, then your close() will return immediately, but the lingering will STILL happen, just in the background, handled completely by your TCP/IP stack...

That's generally what I would prefer to have happen...

(Another use of SO_LINGER is to force a RST to abort a connection, rather than a normal FIN...

People like to do that to avoid TIME_WAIT...

But, that's just a stupid thing to do, and such people should be hit in the head with large, blunt objects...

;-)) I understand what your code is doing, and why you do it...

It makes SOME sense, if you want to be paranoid about any queued unsent data definitely getting transmitted...

Otherwise, if you did a close() (or a shtudown(SHUT_RDWR)), the client could try to send more data, causing a RST from your end, and thereby trashing any unsent data sitting in your send queue...

So, I fully understand your reasoning for doing it, but I was just curious what would happen if you didn't do it, and simply did a close()... Oh, and about the while(read()) loop, it looked to ME as if it could block forever, if the client never closed its end of the connection in response to your sent FIN (via shutdown(SHUT_WR))...

But, that's only true if you have the socket in blocking I/O mode...

If you're in non-blocking mode, then of course, it won't block...

But, if that's the case, then the code as it is isn't really accomplishing the goal you're trying to, either: ie: it may not wait until it gets EOF from the client, but might just fail immediately if there's no data immediately available to read from the client...

So, data may still yet arrive from the client, and cause a RST...

I wonder if maybe that IS happening, and that's what's freaking IE out?

Have you setup a sniffer, and watched the traffic to see exactly what was happening when IE freaks out like that?

:D I started out with just a simple close when I wrote the first 1.0 version of my little server.

It wouldn't work as expected and I often ended up with my child task hanging around in the close.

So I looked into my books and searched through the web.

I also looked at for example the old 1.2 Apache code and things like that.

Also I too would have thought that a shutdown shouldn't be nescessary from my point of view, they all use it and the books also say that it is a good idea.

A short look at the tcp rfc also makes it quite clear that you should do it.

So, what I did back then was simple Code: shutdown(socket,SHUT_RDWR);

Close(socket); and it worked almost like expected then.

Some still got cought up in an eternal fin_wait back then, sitting in the blocked close.

So I built the variable watchdog timer for the childs and ended it by sending a suicide.

In http/1.0 that works fine.

I had no more corpses hanging around and that was it. Now I started out with the persistent connection in http/1.1 and immediatly had problems with IE.

With a short timeout of 5 seconds basically every try to request a page after that timeout occured once gave a blank screen.

So I started to wonder what the heck is going on.

Obviously the connection wouldn't be recogniced as closed from the browsers end.

I again crawled through the web and I found that the "cure" for that new problem would be to make a linger close, but also that the linger thing is often poorly implemented.

The Apache 2 code uses basically the same thing I used in myclose as a work around for platforms were the linger setting causes problems.

So, Apache either sets SO_Linger to active with a value of 2 or 3 seconds, or uses something similar to myclose, also with a timeout set to 2 or 3 seconds in case their recv blockades because of an empty buffer.

The read doesn't block when you first try it, it gives you a 0 for an empty buffer or a -1 for a dead connection.

If you enter it again, it will block as I run the sockets in blocking mode.

Believe me, I have tried that.

The only reason I do the read to empty the buffer is, that there is a statement in the Apache code or manual that a filled buffer might prevent a client from checking the fin on the other end.

So I empty that, followed by an immediat close of the RD buffer so that incoming new data will be rejected.

After that you can happily close. As said, that helps a bit, but is far from perfect.

I tried a simple close too, then basically no browser gets the hint and all try happily to get data from my closed socket until their read times out.

So obviously I have to shutdown my end.

You are right though, naturally the kernel will exactly do the very same thing.

It will also shutdown and it will make a lingering close.

But, as far as I have found out, that will take at least one, in the worst case several minutes.

Straight implemtations of the tcp rfc will need 4 minutes.

A kernel that uses the old rfc as base will never do it and Linux 2.4 uses 1 minute, 2.2 uses 2 minutes and all before that are built upon the old rfc.

And that is obviously what causes the problems if you don't do it "manually".

The close is just there to release control, not to really close the socket itself.

It's like driving a car.

Just taking your hands and feet from the controlls and closing your eyes won't stop the car and won't prevent a possible crash.

So a shutdown is stopping the car and its engine and close after that is leaving it. No, I admit I haven't started to go to the very root of the problem.

That would be the tcp implementation and the coding of the IE.

That are 1 thing I can't change and 1 I don't want to change.

And believe me, knowing myself I would start to re-write the protocol stack once I start, giving me all the direct control I want to.

Or why do you think I write my own server? There are things I have to live with.

Thats tcp and http.

I didn't invent them, else they wouldn't be so....

Never mind. I just try to get along with it without starting to get all worked up into re-inventing the wheel ...

Again. Now I understand my share of the low level stuff, I have designed hardware and I have programmed drivers and created protocols for the communication between controllers and computers for the industry around 10 or so years ago.

I am fairly sure I could also write a thing that looks to the outside like a normal tcp stack but is only a good fake with enough code behind it to serve my special purpose. Again, I can understand the idea why I need to shutdown the socket before the close, also why it might help to clear the read buffer.

Between us, I too think that's rather stupid.

Why can't I flush the buffer?

Why isn't there a way to close for incomming data and then read what is inside it?

Why is there no way to open the line after that again?

Why can't I control the socket directly, like to say don't send so that I can fill the buffer up and the release it or release it right away?

Why can't I change the behaviour of the socket and protocol settings later, during use?

Why can't I say the client directly on either tcp or http to close the connection?

Well, the answer is I haven't designed it and the one that did it was obviously sure that you can't trust a programmer with that kind of control.

Let's just say that the whole thing is crap.

But sadly we still have to use it. HTTP is a stateless protocoll.

Sadly, for a working mangement of a persistent connection you'd have to have a state management.

Without it you have to rely on the lower layers of the communication stack.

This would be tcp in this case.

Now tcp has some means to manage states, so it can actively disconnect from either side.

But, for some reasons we don't have the means to use them directly.

We can only suggest the actions we would want to be done.

So, the close command is the suggestion to finally end the connection eventually.

But there might be reasons why that isn't possible.

For example data could be still in the buffers.

We can't force this data out to prevent that we stick our fingers in the caching mangement of the protocol.

We can only say shutdown.

That is the suggestion that the data, if there is any, is no longer useful and there surely is none waiting to get filled in.

That speeds up the actual closing but still gives no real control.

If there is still data in the readbuffer, tcp will wait that much longer because someone might still want to have it.

The only way to clean that up is to manually read the data out.

This might also free a client that is stuck in a blocked write, so it's actually nice to do it.

All that only encourages a faster finish of the real close, like using you cars horn might wake up the guy waiting at an already green traffic light. I haven't heard much complaints about blank screens from people serfing the web, so I guess that I miss something in that already obnoxious close function of mine.

I tried to work through all of the Apache code, but as they use their own abstraction layers and os modules I have a hard time to find my way through their code.

So I just hope that there might be somebody somewhere that just could say how the heck I get this thing closed in a way that even IE browsers get it.

:(

Don't get me wrong on this.

I normally don't run into a forum and cry for help.

The www with its http and tcp has clearly some problems.

The official tools like close and shutdown just won't do the trick.

I've done a lot work, tests and reading to find a normal way to solve this problem.

When I look at the Apache code for example I see that the guys tempered with protocol settings they shouldn't even be able to access if you go straight after the rfc.

So they try to compensate things for example with a short linger value, what is per definition way out of the spec.

I just don't want to loose anymore time to solve a problem that obviously can't be solved in a "right" way, else there would be somewhere an article that just states "that's how it's done".

And I am also a bit fed up trying to figure out a way out of the mess that others have made in the first place. When I look at the tests and the text of the http rfc from the beginning of the persistent connection idea and then look at all those discussions I have seen in the web from the early days until now, I can only come to the conclusion that we are in that mess because people tried to read something into the rfc that wasn't meant to be.

If you want we can discuss this deeper, but it won't solve my problem.

I don't want to dive into the protocol timings with a sniffer. I shouldn't have to and I shouldn't have to temper with those settings.

The protocol stack is there to keep me away from exactly that.

I have done all that could be done without violating standards.

I have used over 80 hours in research time, reading texts from all over the world that are related to http, sockets, tcp and what not.

So, is there anybody out there that has a piece of code that solves the close at least in a way that he can say it won't get any better than this.

Quote: : A short look at the tcp rfc also makes it quite clear that you should do it (referring to shutdown ).

Perhaps you should read the TCP RFC again.

I am pretty sure the TCP RFC does *not* tell one to use the shutdown socket API as the only proper way close down a socket connection (in fact, though I have not read it recently I would be surprised if it mentioned much about the socket API as such an API is not required for a proper TCP implementation). A proper TCP implementation *does* need to handle all the states and packet sending properly and that includes the sending of FINs and the TIMEWAIT state but how an application asks the implementation to do this is left open (i.e.

The API). The Unix/POSIX socket API of course originated with BSD and does have its usefulness.

For example, you mention problems with terminating children with a timeout.

Shutdown normally just forces the TCP layer to send the FIN and allows other socket calls to return errors if someone tries to use the socket inappropriately.

This can be useful if a descriptor is shared between processes (like via the parent-child relationships).

A simple close though will also initiate the sending of the FIN (among other things). Perhaps shutdown has other uses I am not aware of but to my mind it is mostly only useful for forcing half the TCP connection to shutdown (and making it act more like simplex connection vs.

A duplex one) and possibly waiting for the response (e.g., EOF socket condition for FIN;

But there are also others like RST and timeout), or to force the socket to be unusable (while also tearing down the TCP connection) which as I mentioned could be useful if the socket descriptor is shared between processes (technically I believe each process has a different copied descriptor that accesses the same TCP connection--both must be properly closed so one does not have a descriptor leak;

Exiting the process of course automatically closes all the descriptors used by that process which will shutdown the TCP connection if it is the last descriptor referring to that connection). As Rob mentioned, SO_LINGER is really only useful for forcing close to block until data is sent (perhaps one of the few ways to "flush" a TCP connection but it also tears it down as a side effect) or to force a TCP connection to be forcible deleted (yeilding RSTs).

Also as Rob mentions forcing such socket TCP connection deletions to avoid TIMEWAIT is not really very sensible but forcing RST maybe could be useful for testing such an RST condition (but one could resort to raw sockets for this provided they have priviledges to do such). If you are timing out children that service HTTP requests and forcibly killing them then you are not that concerned with making sure every peice of data gets to the other end (as TCP will do its best effort and users can always reload pages), so I recommend just simply shutting down the socket (so parents or children cannot use the same connection) and then proceed to close it and not messing with SO_LINGER or waiting for anything else.

Yeah, what Uzume said...

Trust me, shutdown() is NOT required for normal use...

I've been writing sockets code now for close to 15 years, and I can tell you I have had very few rare times that I've ever needed to use shutdown() for any reason...

Most of the time, I simply close() my sockets, and that's it...

That's really, truly ALL that one needs to do...

Honestly... And, no, there's no delay or timeout of any sort that goes on after you do the close() before the TCP/IP stack will send the FIN...

It does it immediately, as soon as you close() the last open copy of the socket FD...

Trust me, I'm quite positive on this...

If your close()'d sockets aren't sending FINs, then my guess is that you have an FD leak somewhere, and have another copy of that socket FD open...

If you're getting blocked in close(), as I think you stated at one point, then I think you must have set SO_LINGER, because in normal cases, that should never happen: close() should just return immediately, and the actual shutdown of the socket should take place in the background...

If your sockets are getting stuck in FIN_WAIT*, as you also mentioned once, then that just means that your TCP stack is waiting for the FIN from the other side of the connection, having already sent its FIN to them...

Specifically, FIN_WAIT1 means it hasn't even gotten an ACK back for its sent FIN, yet; and FIN_WAIT2 means its FIN has been ACK'd, now it's just waiting for the remote FIN to come in...

In other words, such a situation means that the client (in this case, a web browser of some sort) has not actually closed its end of the connection for some reason, despite you closing your end already...

It's not a problem with anything on YOUR end, but rather a bug in the client, where it presumably fails to detect that you've closed your end of the socket...

Not much you can do about that, really... Now, if instead of FIN_WAIT*, you really meant TIME_WAIT (which I get the impression you might have, since you mention timeouts of 1 to 4 minutes, which are typical for TIME_WAIT timeouts, then that's a completely different matter...

TIME_WAIT is something that's SUPPOSED to happen, not a problem...

The sockets SHOULD hang around in TIME_WAIT state for a few minutes;

It's done for a very good reason , and shouldn't be avoided... As to what is really causing your problem with IE, I'm still not sure...

But, if it were me, I'd do as I already suggested, and setup a packet sniffer on the line (preferably one on the server side and one on the client side, both), and see exactly what the network traffic looks like when IE freaks out like that...

My gut instinct is guessing (blindly in the dark) that IE is trying to write down a broken pipe, and getting a RST, and that's what's freaking it out... In other words, it's too damn stupid to have detected that you already closed your end of the socket, before it tries to write to it again...

If that's the case, I think the only solution might be to sit blocked in a read() loop, of the sort you have, but one that truly blocks until EOF (ie: FIN from the client)...

Of course, that's not ideal, and rather defeats the point of your local timeout for closing down the socket, I know...

Because, it still puts you at the mercy of IE's timeout (or until the user tries to get another page)... But, if that's what's going on, I don't know how else you could really work around it...

Aside from just increasing your own local timeout to at least as much as whatever IE's is...

*shrug*

Might be I mixed up a couple of texts I've gone through.

I think I've read a commend from the guy that made the tcp rfc where he mentions one should use shutdown then. Code: /* we now proceed to read from the client until we get EOF, or until * MAX_SECS_TO_LINGER has passed.

The reasons for doing this are * documented in a draft: * * http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt * * in a nutshell -- if we don't make this effort we risk causing * TCP RST packets to be sent which can tear down a connection before * all the response data has been sent to the client.

*/ #define SECONDS_TO_LINGER 2 AP_DECLARE(void) ap_lingering_close(conn_rec *c) { char dummybuf[512];

Apr_size_t nbytes = sizeof(dummybuf);

Apr_status_t rc; apr_int32_t timeout;

Apr_int32_t total_linger_time = 0;

Apr_socket_t *csd = ap_get_module_config(c->conn_config, &core_module);

If (!csd) { return;

} ap_update_child_status(c->sbh, SERVER_CLOSING, NULL);

#ifdef NO_LINGCLOSE ap_flush_conn(c);

/* just close it */ apr_socket_close(csd);

Return; #endif /* Close the connection, being careful to send out whatever is still * in our buffers.

If possible, try to avoid a hard close until the * client has ACKed our FIN and/or has stopped sending us data.

*/ /* Send any leftover data to the client, but never try to again */ ap_flush_conn(c);

If (c->aborted) { apr_socket_close(csd);

Return; } /* Shut down the socket for write, which will send a FIN * to the peer.

*/ if (apr_shutdown(csd, APR_SHUTDOWN_WRITE) != APR_SUCCESS || c->aborted) { apr_socket_close(csd);

Return; } /* Read all data from the peer until we reach "end-of-file" (FIN * from peer) or we've exceeded our overall timeout.

If the client does * not send us bytes within 2 seconds (a value pulled from Apache 1.3 * which seems to work well), close the connection.

*/ timeout = apr_time_from_sec(SECONDS_TO_LINGER);

Apr_socket_timeout_set(csd, timeout);

Apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1);

While (1) { nbytes = sizeof(dummybuf);

Rc = apr_recv(csd, dummybuf, &nbytes);

If (rc != APR_SUCCESS || nbytes == 0) break;

Total_linger_time += SECONDS_TO_LINGER;

If (total_linger_time >= MAX_SECS_TO_LINGER) { break;

} } apr_socket_close(csd);

Return; } That's directly from the Apache 2 code.

I've built in the myclose thingy after I've found several other examples that use more or less the same thing.

And I only tried it because I encountered problems with just close, less with shutdown+close. To my child kill routine....

Basic overview how things are done: Father waits for connection. A valid connection is encountered ->

Process forks father closes the accepted socket, sets child timout to 120 secs Son closes all father only sockets Son checks the size of the file and changes the timeout (eg 1000 secs for 200KByte, should be pretty enough) After son has data sent it sets timeout back to 120secs and waits for the still open persistent connection to be used, with a timeout son repeats that intil a connection: close is encountered or the connection times out son sends the father a signal for suicide and tries to shutdown+close the socket and exit father sets the timeout to 5 secs upon receiving suicide.

If, and only if the son process is still there after at least 5 secs have passed, it will tear down the task with a kill signal. So, if all works normal, the kill won't be used.

The kill is basically there to get rid of tasks that hang because of errors in the cgi layer and in case the close or exit won't work properly. The standard seems to be for the task to hang in the exit until the OS has closed the socket completely.

That may take up to 1 minute according the man pages about the tcp on my machine.

It's my impression that if I linger with my task for a shortend while before I exit that this will work around the OSs linger and shuts down the child normally.

I've looked with netstat and while all my other processes that are not part of the server core leave a trail of time_waits behind, there are none to be found that are related to the core.

So it seems to work in a way. So, in case I don't use a short linger and only close,that is what happens with IE.

It tries to load a page and hangs.

It does so until the time_wait entry vanishes, then IE displays a can't connect to server.

With a short SO_Linger of 2 or 3 secs and the close+shutdown IE only displays this page if a new load operation is started within a fraction of a second after the shutdown+close is done.

With only close IE brings up an empty page that seems to contain up to 19 spaces or other not displayable chars.

The only way around that I found sofar is to wait 60.3 seconds in an idle connection, as IE then closes it by itself.

If I shutdown+close without the use of linger, IE will also bring an empty page whenever a request is made between my side timed out and this 60.3 seconds. All other Browsers I tried don't have this problem.

Just because of that I started to experiment with other ways to close a socket.

It really wasn't my idea in the first place.

What I am trying to do is to get rid of the short time where the IE still runs into the "server not found" issue.

Nothing more, nothing less.

It's really not my fault that there is no way to properly announce a timeout for idle connections in http.

I've tried to send back a "Keep-Alive: timeout=20" but that isn't used by IE or any other Browser these days and isn't part of the 1.1 spec. Currently I set the SO_Linger time to 3 and just use a normal shutdown+close.

That's the thing with the least problems enountered and with the shortest time IE will produce an error.

What I wanted to know is if there is a way to shorten this "possible error time" or get rid of it completely without waiting 60+ seconds and together with persistent connections.

The Quote: d Apache code just states exactly what I said: the usefulness of doing the shutdown(SHUT_WR), following by a read until EOF, then close(), is purely to prevent RSTs caused by a client sending more data from trashing any unsent data in your send queue...

That's perfectly true and reasonable...

It's just that I rarely have a need for such behavior myself (since I'm usually coding both the server and the clients that are interacting with it, and I give them sane, well-behaved protocols, not crap like the mess that HTTP is ;-))...

If I had to write a server to handle a messy protocol implemented by a wide variety of different clients written by many different people, I'd probably need to be more paranoid, if I wanted to make sure that all data was delivered...

;-) But, that's all it is for: making sure that data that you already sent before closing gets delivered successfully to the client...

It's got nothing to do with necessity for proper functioning of TCP...

Nor anything to do with TIME_WAIT or FIN_WAIT* states...

It's just a data-integrity paranoia measure...

(Also, the use of "linger" within that posted code seems to have little to do with actual SO_LINGER...) I'd like to know just what man pages you're looking at which say that an exit() can hang for upto 1 minute while sockets are being closed??

I've never heard of such a thing, and I would consider it utterly insane and unacceptable, myself...

The only thing I can see that may be what you're talking about (assuming you're on a Linux system, which I think you mentioned before) is the documentation on the "tcp_fin_timeout" sysctl...

But, that doesn't say anything about your exit() or close() hanging for that long; it's merely how long the TCP stack will wait for a final FIN before trashing the FIN_WAIT* state...

But, that should be done in the background by your TCP stack, and NOT require blocking your app's close() or exit() for that wait period...

I've, personally, never seen such a thing, or even heard of it, short of someone using SO_LINGER (which explicitly asks for close() to hang like that)... But, even there, an exit() shouldn't hang, because I believe it's officially spec'd that any exit()-time closes should always linger in the background, regardless of SO_LINGER setting... Your other comments make it sound like all you're accomplishing with your low SO_LINGER setting is forcing a RST of the connection, thereby improperly avoiding your TIME_WAIT state... As I said above (and linked to a source explaining why), you should NOT try to avoid TIME_WAIT like that;

TIME_WAIT is your friend, and is there to help you...

Avoiding it like that is very dangerous and ill advised...

Sockets in TIME_WAIT are not an indication of something wrong, but rather of proper behavior!

Well, I stay corrected. So now, I have thrown out all but the disabling of the nagle.

I've also discarded all shutdowns that were just additional to a regular close. Indeed, all browsers but the IE ones behave just like before, at least in the lan, have yet to try how are things on the server in the web. As I said earlier, without all that "additinal crap", IEs just always bring a server not found error on the first try after I closed the persistent connection.

And there it plainly just doesn't matter if it's a lan with a ping of 30ms and no packet loss what-so-ever or in a web slum.

Netstat states that my side sticks in the CLOSE_WAIT until the IE itself times out after 60-61 seconds.

So, any ideas how I could try to kick that IE? The hanging close was there when I first tried to write a few small things.

I think it was on an early 2.0 kernel with a SuSE 7.

It passed all the lines until the last command, that was the close, and my task never finished. The process was not a zombie just waiting for the parent to look after it, it was still fully there until the time_wait finished.

That only stopped when I used the shutdown prior to closing.

It might be though that it was a bug in the lib rather than anything else.

I just never stopped to use that combination as it had no major drawbacks. When you encounter a strange bahaviour you start to look around and try to find some explanation, however dumb it might seem as long as it helps when you use it.

Doesn't matter much if the reasoning is ok or not.

You say your side is in CLOSE_WAIT state??

That's odd... That indicates that you have NOT actually done a close() yet, but the other side HAS...

Ie: you have received a FIN from the remote side (IE in this case), but your local app has yet to recognize this fact, and close its end, so your stack can send its FIN...

Perhaps you have some bug where you're not detecting the closure of the remote end of the connection, or not properly closing you end in that case?

I've also wondered about that and taken a look at the code it goes through.

Well, as a left over from before, the timed out persisitent connection did go through the same piece of code the pipelined one used when too many pipelined requests are made, so there was a shutdown of read.

The pipeline code then sends all the data out and shuts write before close, but the code for ending the persitent connection just closes.

That's most likely why I got a close_wait status, the IE started to close the connection after me closing the read without pending write. I've now taken the shutdown for read out, better said, I don't go through the same code anymore, so there is just a close now.

Now it works for the requests during the persistent connection and it works for most cases coming in ~2 secs after the close was made.

All requests fail during the 2 seconds right after my close command.

In this time the socket is in FIN_WAIT2.

Seems it's still marked as usable in IE and it tries to use the closing down connection for its request. When I look now at the code from the Apache guys it makes some more sense to me.

They say the 2 secs are a value they got through experience.

As all other browsers work obviously without that, it seems only to be in there to avoid the IEs 2sec problem.

If I understand it (now) right, the shutdown of WR causes basically a closing of the socket without a real close from my end.

If the IE sends a request before all the closing is finished it will fill my buffers without causing a reset/error on IEs side. So, if there is no such error it then sees that the connection was down when it started and just resends its request.

So all I have to do now, is in case of a timed out persistent connection to wait for additional 2 to 3 secs in a blocked read and then close RD and then the socket. How can I do this the right way?

Well, there are a variety of ways to do a read with timeout...

Most people these days go with non-blocking I/O and use select() to do the timeout...

That has the advantage of being thread-safe (if you care about that;

But, it's also good even for single-threaded apps)... The other common method is to use alarm(), and setup a SIGALRM handler (which either just returns, kicking you out of your blocked read() with EINTR, if your system doesn't auto-restart interupted syscalls;

OR, you can have the handler do a siglongjmp() back into your code, which should always work, but is rather messy to deal with)...

I used to be a fervent alarm()-based timeout person, myself, but these days I'm a big fan of non-blocking I/O + select()...

So, I tested for the past several hours. Reading of the incoming request after write is closed doesn't help much, a bit, but not much. It is possible to send before closing of write and then the IE uses this data if, and only if a request is send before the socket is entirely closed.

Sadly, all but the Operea one won't discard this data even after the socket is closed.

So the use is limited and I would have to make a check for IEs. If I reduce the receive buffer size of the socket to 0, right before closing the write, then IE seems never to display a blank page or an error message as long as the request was NOT made with a javascript location- href command.

Even if the close follows right after the wr-shutdown as long as I don't make a rd-shutdown too.

The rd-shutdown only then makes no problem if I wait (with a sleep) for at least 3 seconds in between. So, I even once had a receive while the socket was already in fin2 with a js location href call.

But only if the page was already in IEs cache.

Seems never to happen with unknown pages.

So my guess is, they look if the socket is still valid and then look in the cache when they create the data for the request to get the http-headers for it.

This search in the cache seems to be the max time the IE misses the closing of the socket (+ ping time?).

They seem also to use different code for js and the normal html. I wonder if the same happens with for example Apache.

Does it also produce a blank page or an error in IE if someone hits a button with an onclick location.href right at the moment the connection times out?

Quote: : So now, I have thrown out all but the disabling of the nagle.

I wonder why anyone would want do disable Nagle on a web server?

They are not exactly real-time or anything (I could maybe see it on a telnet server or the like).

In a HTTP/1.0 environment Nagle really doesn't make much of a difference (but doesn't help either).

In HTTP/1.1 with it's persistent connections the small delay times sum up as the next request usually won't come in before the last bit of information is received by the client.

Only Mozilla with enabled "pipelining" (disabled by default) sends the next request out as soon as data of the current one comes in, negating the effect of disabling the Nagle.

If I remember right, Nagle might delay data up to 0.2secs.

With easily 10 to 20 requests on a single persistent connection that'll be 2-4 seconds longer load times and a 2-4 seconds longer occupied socket, worker task or thread.

As I do buffering on my own and burst feed the connection, I can fill the packets without Nagle anyway, so why should I want to keep it active?

I finally found what caused the problems with IE.

My server processes headers it gets from my other applications in order to manage the persistent connections.

So it takes for example "Connection: close" header fields out if nescessary and it puts some other stuff in that the one or other browser might need.

While doing that the length of the header was updated for the added content, but not for the taken out connection thingy, which sums up to 19 bytes including the \r\n at the end of the line. So when the routine sent the whole data back it did send 19 additional bytes filled with 0 back (header_length+19+content_length).

So the receive buffer did hold 19 bytes after a request and the IE broswer used that to indicate that the connection was still valid, sending out requests on a socket that was actually already closed or about to close.