Why do you need to "make sure it's alive"? [...]
Because if the client is completely finished, there's no reason to keep
threads open, and there are other things that need to be done in the
program after a user has "signed off".
If the client is completely finished, it should close the connection
gracefully using shutdown() or similar API, which will be signaled to you
by a successful completion of a receive, with zero bytes.
I understand the way TCP works, but I've always been able to tell
in the past when the other side decided to end the connection.
(see below select() comments)
TCP does allow for telling when the other side decides to close the
connection. But it doesn't do so by providing you a way to poll for the
"connectedness" of the socket.
Well, that was just pseudo code, there are times when I need to send
things to the client on certain events.
That's fine. You just can't use the thread waiting on the Receive()
method to do the sending, since it's blocked. Do the send from a
different thread.
Yes it will. If you call select() and the socket has been gracefully
closed by the other end, then it will return > 0.
It also returns a value greater than zero for successful receives,
connections, accepts, etc. All that select() is telling you is that some
sort of i/o event happened. It does NOT tell you whether the socket is
connected or not. For example, when using select() if the remote end
closes the connection, select() will still return a number greater than
zero, and indicate that the socket is ready for you to call recv() on it.
That call to recv() will succeed, but with a return value of 0 bytes read.
In other words, select() isn't telling you the connected state of the
socket, receive() is.
Create a socket via socket(),
and connect with connect(), then in a timer, or in a thread keep
checking fdRead with select(), if you close the other end of the socket,
you will go into select().
Why would you poll AND use select()? That's really broken code that does
that. The whole point of select() is that you can hand it a bunch of
sockets and have it block. If all you're doing is polling, you might as
well just set the socket(s) to non-blocking and poll them directly. Using
socket() in that scenario buys you nothing.
THEN you can call recv(), which will tell you it's closed.
Yes. As I wrote above, it is the recv() method that tells you whether the
socket is closed or not. The select() method doesn't do that, and you
don't need to call it at all to get the information that recv() gives you.
There IS a way to do it the old way.
And you can do it in the new way too, and it works just like it works in
the old way.
In MFC you get OnClose() instantly when the client closes their side of
the connection.
Both of these methods don't tie up the thread, but let you know
when the other end has gracefully closed.
Only because they are both waiting for some i/o. I don't know how MFC
implements its OnClose() method, but Winsock provides for a wide variety
of mechanisms to deal with notification of socket i/o events. But in
every case, *somewhere* something is waiting for the i/o to happen. And
the detection of the closure of the connection *always* involves the i/o
actually occuring and being detected as a closure of the connection.
Whether this is done via a call to receive() that returns zero bytes, or
some lower-level mechanism that looks at the underlying FIN IP datagram
and sends an FD_CLOSE message (WSAAsyncSelect()) or sets an event
(WSAEventSelect()) or does something else, the closure is not detected
unless there's some i/o that signals the closure.
No, I'm not talking about non-blocking, same as straight forward old
CSocket and socket().
Um...I can't speak for CSocket, having never used MFC's implementation,
but non-blocking and socket() are not mutually exclusive at all. In fact,
most well-written socket applications use the socket returned by socket()
with non-blocking semantics.
You brought up select(), which should only be used with non-blocking
sockets. It makes no sense to use it with blocking sockets, since there's
no guarantee that after select() returns an indication that a socket is
ready for reading or writing, that reading or writing can actually occur
successfully. With a blocking socket, you could wind up blocking on the
send() or recv() function call right after returning from select().
If you're not talking about non-blocking sockets, I don't understand why
you mentioned the select() function.
#2 is something I will research. My thread works well because it lets me
keep up with "session" like data (not to be confused with internet),
like a
user id who is connected, user states, and other connection specific
information.
There's no reason you can't do things the way you're doing them now, so
long as you understand that dedicating a thread to each connection won't
scale very well. Performance will suffer, and you'll reach the maximum
number of threads possible long before you reach the maximum number of
clients a socket-based server can actually handle. But for a small number
of clients, if it simplifies the overall code you may find it's better to
just use a thread-per-connection design.
But even so, it's important to understand what's possible and what's not,
and what's an appropriate use of the API. You should never poll, and you
cannot rely on a simple test to detect whether a socket is connected.
Without i/o there's no way to know if the TCP connection is still
connected. None of the various Windows APIs that support TCP provide
connectedness information without some i/o happening.
Pete