|No such thing as a small change|
Re: IO::Select and correct way to detect client crashed?by andal (Hermit)
|on Oct 19, 2012 at 07:19 UTC||Need Help??|
Well, I would recommend to look not into perl, but into TCP protocol, since you are using it. This protocol is not hidden away from you, you have to manage the events produced by the protocol stack.
From the perspective of the protocol, you make quite a few mistakes. First of all, when using "select" one should make sockets non-blocking. For example, there's no guarantee that "accept" will return socket after the "select" has marked it as ready. By the time you call this function, kernel could have removed the socket, so you would end up blocked in the "accept" waiting for next connection. Of course, probability of this event is small, but you want to have robust program, right?
Next thing. The TCP is "stream" protocol. So, you can not know how much of data is available for reading when your socket is marked as read-ready. You may get only 2 bytes out of expected 4, but when you call "recv" you'll get those 2. Your code is not prepared for that. It simply would throw away those 2 bytes.
Writing to TCP socket also requires care. There's no guarantee that the peer will read quickly. So, you may fill up your system buffers (if you write a lot) and then your call to "send" will block (if the socket is blocking), or won't write everything, which you don't check.
And now concerning your question about detecting presence of peer. As someone here already mentioned, if the peer has closed connection, or crashed (application crash), then your end of the socket shall become "read-ready", but when you try to read from it, you'll read 0 bytes. In this case you know that the peer is gone and you should close your socket.
There's a catch here. If the peer has crashed when you write to it, then you won't see the 0 bytes input. In this case, your write may result in EPIPE error, actually by default it is passed as signal killing your whole application. So, you may want to pass "MSG_NOSIGNAL" flag to function "send" to prevent it. But if your write is short, then you'll get your socket "read-ready" after it, and you'll read the 0 bytes input, indicating that the peer can not accept your input any more.
Finally. Don't put small timeout for "select" call. Why should you do anything, if you don't have any sockets ready? Real application would need support for timers, the presence of timers would define the time-out for "select" call. If you need timers, then use something like GLib events loop instead of "select".
Again, all of the above stuff comes from knowing TCP protocol. You should know how the connection is established on the protocol level, you should know, how the data is passed, how the errors are communicated between peers and between protocol stack and the application. I encourage you to read "Unix network programming" written by Stevens. This book provides very complete description of networking.