We help IT Professionals succeed at work.

How to Determine if a Socket Connection is still Good?

magenta
magenta asked
on
Excuse the naivete of the question, but what is the right way to determine if a socket connection is still good? Of course, if I try to send or receive data on a bad connection, the call will fail, but is there a way to check the state of a connection without necessarily trying to send or receive data?

Consider the following example. Say I have a client that connects to a server, and the server periodically sends data to the client. In between sends, the server does some work. How can the server know if the client has disconnected, without sending the client any data? In other words, is there anyway that the server can test the connection while it is still doing work, so that if the client were to disconnect, it would immediately know it and not later on when it tried to send data. Obviously, I don't want to impose some kind of ping or ack in the protocol between the client and the server.

I've looked into using select() but I am not sure that this fits the bill.

I have done some testing however, and I've come up with the following. The server can "test" the connection by periodically sending 0 bytes to the client. In my testing of this idea, I've found that the server will immediately detect the client disconnection the next time it sends 0 bytes to the client. Also, the client doesn't seem to "notice" the 0 bytes sent to it. In other words, sending 0 bytes doesn't seem to cause a problem.

The advantage of my scheme seems to be (1) it's very simple, (2) it doesn't require any kind of ping or ack protocol between the client and the server and (3) it's very simple! :) However, I'm sure that there's probably a better way to do it...

Thanks,
Frank
Comment
Watch Question

May be you can simple use function IsInternetConnection
from
http://www.codeguru.com/internet/IsINetConnection.shtml
why doesn't select work?
have a look at this:
http://www.experts-exchange.com/jsp/qShow.jsp?qid=20191532
maybe it's interesting to you.

Author

Commented:
AlexVirochovsky, the IsInternetConnection() function seems to be more about detecting whether or not a computer is connected to the Internet than what I'm looking for.

Author

Commented:
Schuhschrank, my problem with select() is that it seems to more about determining the state of a socket (as in readable or writable) that for just determining if the connect is still valid. Obviously, if the connection is lost then the socket will be neither readable nor writable, but I'm looking for a more explicit way of determing if a connection is still good.

However, I have tested using select() and what I am seeing is that select() returns 0 (timeout) when the connection is lost. I am using a 1 second timeout parameter. So, in other words, is it safe to say that if select() returns 0, then the socket is disconnected?

Thanks,
Frank
If the remote machine is kinda slow it might be possible that it needs more than one second to respond. Therefore reading from a socket would not work but presently I cannot think of a situation in which sending would be impossible. AFAIK that should only be the case after the remote side has called shutdown() or closesocket().

Author

Commented:
Does a call to select() cause some kind of network transmission? In other words, is the call to select() purely determined by the socket end it is run on, or does it involve some kind of commnication with the other end?
What kind of transmission should that be? As far as I know select() does not transmit anything but you can just try it: Create a socket and make a for(;;) loop with a select in it. Set timeout to 1 msec and see if anything goes through your connection. You don't even need a packet sniffer. Just look at the connection status and check if the number of bytes sent is growing or not.

Author

Commented:
Problem I have with select() is that I cannot tell if the connection was closed. Maybe I am calling it wrong, but the call to select "timesout" both under normal operation and when the connection is closed. Why doesn't select() return error if the connection is closed?
OK, you can use WSACreateEvent() and WSAWaitForMultipleEvents() but that makes your socket non-blocking and it works with non-blocking sockets only. At least I did not succeed at making WSAWaitForMultipleEvents work correctly after setting the socket back to blocking mode using WSAAsyncSelect (with lEvent == 0) and ioctlsocket(). You might find the following code interresting if you have no problem with non-blocking sockets, though.

#include "winsock2.h"
#include "stdio.h"
#include "conio.h"

SOCKET s;
WSAEVENT hEvent;
bool waiting;

DWORD WINAPI WaitingThread(LPVOID pParam)
{
     printf("\nwaiting for events\n");
     WSAWaitForMultipleEvents(1, &hEvent, false, WSA_INFINITE, true);   //wait until FD_CLOSE occurs
     printf("\nconnection closed\n");
     waiting = false;
     return 0;
}

void main()
{
     WSADATA wsa;
     WSAStartup(MAKEWORD(2,0), &wsa);
     
     s = socket(AF_INET, SOCK_STREAM, 0);

     HOSTENT *pHE = gethostbyname("localhost");
     
     sockaddr_in sa;
     memset((void*)&sa, 0, sizeof(sockaddr_in));
     memcpy(&sa.sin_addr, (pHE->h_addr_list[0]), 4);
     sa.sin_family = AF_INET;
     sa.sin_port = htons(8000);

     hEvent = WSACreateEvent();
     WSAEventSelect(s, hEvent, FD_CLOSE); //this sets our socket to non-blocking mode!

     connect(s, (sockaddr*)&sa, sizeof(sockaddr_in));

     SECURITY_ATTRIBUTES secatt;
     secatt.lpSecurityDescriptor = NULL;
     secatt.bInheritHandle = false;
     secatt.nLength = sizeof(SECURITY_ATTRIBUTES);
     unsigned long tid;
     waiting = true;
     ::CreateThread(&secatt, 0, WaitingThread, NULL, 0, &tid);

     char ch;
     
     for(;waiting;)
     {
          if (!waiting) break;
          printf("\npress q to continue or any key to recv()...\n");
          ch = getch();
          if (ch == 'q' || !waiting) break;
          char buffer[256];
          printf("calling recv()\n");
          recv(s, buffer, 256, 0);
          printf("recv() returned\n");
     }

     if(waiting)
     {
          closesocket(s);
          printf("closesocket() called\n");
     }

     printf("\n\n\n\n\n\npress any key to continue...");
     getch();

     WSACleanup();
}

Author

Commented:
Well, a blocking socket is perfect for the application and a non-blocking socket is considerably more complicated to code, so I'd rather not change. At least, not unless I have no choice...

However, a few things:

I tested using select() some more and noticed that if the socket is closed, select() returns 2, which doesn't make sense because the number of sockets passed to select() is 1. If the number of sockets passed in is 1, then select returns either SOCKET_ERROR (-1), 0 (timeout) or 1---how can select() return 2?

Also, someone told me that the Berkely socket poll() call will return POLLHUP if the socket has been closed. Unfortunately, there is no poll() in WinSock. :(

Thanks,
Frank

Author

Commented:
My mistake on select(). It can return greater than the number of sockets passed, because it returns how many bit map entries were set. I set the same socket for all three bitmaps, hence, 2 is ok.

However, my problem with select remains that I cannot reliably use it to determine if a connection has been lost.

Thanks,
Frank
Under which circumstances can select() return 0 for writable sockets if the connection has not been closed?
However, if you told me a little more about what you want to do I might come up with some other idea. For example, if you really want your program to send without receiving, you might start a thread with nothing but a read() in it. As soon as that read() returns you change a global variable's value. Then you can check that variable and see if the remote side has diconnected.

Author

Commented:
Schuhschrank, select() can still return with one or more bitmap entries set on a closed socket. In other words, select() can return the same values for both open and closed sockets! In fact, by definition select() works on a socket in any state. On Unix, you have poll() which returns POLLHUP when the connection is closed. However, there is no poll() in WinSock.
magenta, I am not talking of the return value.
select can take 3 FD_SETs as parameters and modifies them.
If the FD_SET for writable sockets has its fd_count value set to 0 after select returns the connection can hardly be good.
However, if you dan't want to use select, let's consider that thread-thing. Maybe that's working better.

Author

Commented:
Schuhschrank, in my tests, select() returns write set for both good and bad connections. I'm calling select() with a 1 second timeout and with only the fd_set for writefds. In all cases, select() returns 1 and with the writefds entry set. Does that make sense?
Strange indeed. OK, let's concentrate on another approach.
Does your program only send data or does it have to receive, too?
ADMINISTRATION WILL BE CONTACTING YOU SHORTLY.  Moderators Computer101, Netminder or Mindphaser will return to finalize these if they are still open in 7 days.  Experts, please post closing recommendations before that time.

Below are your open questions as of today.  Questions which have been inactive for 21 days or longer are considered to be abandoned and for those, your options are:
1. Accept a Comment As Answer (use the button next to the Expert's name).
2. Close the question if the information was not useful to you, but may help others. You must tell the participants why you wish to do this, and allow for Expert response.  This choice will include a refund to you, and will move this question to our PAQ (Previously Asked Question) database.  If you found information outside this question thread, please add it.
3. Ask Community Support to help split points between participating experts, or just comment here with details and we'll respond with the process.
4. Delete the question (if it has no potential value for others).
   --> Post comments for expert of your intention to delete and why
   --> YOU CANNOT DELETE A QUESTION with comments; special handling by a Moderator is required.

For special handling needs, please post a zero point question in the link below and include the URL (question QID/link) that it regards with details.
http://www.experts-exchange.com/jsp/qList.jsp?ta=commspt
 
Please click this link for Help Desk, Guidelines/Member Agreement and the Question/Answer process.  http://www.experts-exchange.com/jsp/cmtyHelpDesk.jsp

Click you Member Profile to view your question history and please keep them updated. If you are a KnowledgePro user, use the Power Search option to find them.  

Questions which are LOCKED with a Proposed Answer but do not help you, should be rejected with comments added.  When you grade the question less than an A, please comment as to why.  This helps all involved, as well as others who may access this item in the future.  PLEASE DO NOT AWARD POINTS TO ME.

To view your open questions, please click the following link(s) and keep them all current with updates.
http://www.experts-exchange.com/questions/Q.20115902.html
http://www.experts-exchange.com/questions/Q.20123776.html
http://www.experts-exchange.com/questions/Q.20184557.html
http://www.experts-exchange.com/questions/Q.20192504.html
http://www.experts-exchange.com/questions/Q.20245395.html
http://www.experts-exchange.com/questions/Q.20254214.html
http://www.experts-exchange.com/questions/Q.20271357.html
http://www.experts-exchange.com/questions/Q.20279551.html
http://www.experts-exchange.com/questions/Q.20286253.html
http://www.experts-exchange.com/questions/Q.20291661.html
http://www.experts-exchange.com/questions/Q.20294731.html

To view your locked questions, please click the following link(s) and evaluate the proposed answer.
http://www.experts-exchange.com/questions/Q.20286299.html

*****  E X P E R T S    P L E A S E  ******  Leave your closing recommendations.
If you are interested in the cleanup effort, please click this link
http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=commspt&qid=20274643 
POINTS FOR EXPERTS awaiting comments are listed in the link below
http://www.experts-exchange.com/commspt/Q.20277028.html
 
Moderators will finalize this question if in @7 days Asker has not responded.  This will be moved to the PAQ (Previously Asked Questions) at zero points, deleted or awarded.
 
Thanks everyone.
Moondancer
Moderator @ Experts Exchange

Author

Commented:
Sorry, I wanna close this question.

None of the help from experts really assisted me. What I found that worked in the long run is to do a send() of 0 bytes on the socket. If the connection is closed, then the send() will fail and WSAGetLastError() will return a connection closed by remote host error.

Thanks,
Frank
300 points have been refunded to you and this question closed by moving it to our PAQ at zero points where it can help others.  Thanks for adding the solution you found and implemented.
Moondancer - EE Moderator