LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   How could server detect closed client socket using TCP and c++? (http://www.linuxquestions.org/questions/programming-9/how-could-server-detect-closed-client-socket-using-tcp-and-c-824615/)

Lobinho 08-06-2010 11:31 AM

How could server detect closed client socket using TCP and c++?
 
Hi,

Reading some examples on net and copying some codes I was able to build a (frankstein) server that accept connection from one client and receive and send messages to it. The big problem that shows up is that I don't know when client disconnects from my server.

I've been looking for a solution, but no success. I'd read about SO_KEEPALIVE option (which could solve my problem), but I don't know how to use it (how to check the value of it).

I can't use ping because the server (machine) could be running, but not the client (software).

Anyone knows a good tutorial or how to (for beginners like me xD) of TcpIp sockets using c/c++ and how to detect when a client disconnect?

ps: I don't know sockets very well

Thanks in advance.

paulsm4 08-06-2010 02:40 PM

Actually, that's an interesting question - with a nontrivial answer.

Here are a couple of links. I'd also recommend getting Stevens: "Unix Network Programming"

Quote:

http://stackoverflow.com/questions/7...-server-socket

Q: How can I detect that a client has disconnected from my server?

A: Since there are no events available to signal when the socket is disconnected, you will have to poll it at a frequency that is acceptable to you.

http://forums.sun.com/thread.jspa?th...39297&start=15

Q: TCP client application does not detect network failure

A: You're tripping over a basic reality of How TCP/IP (and hence the Entire Freakin Internet) Works. Go find Stevens' "UNIX Network Programming" (ISBN 0-13-490012-X.), and read it. Then read it again.

Repeat until the giant glowing lightbulb appears over your head and an angelic chorus of deceased network engineers descends from the heavens repeating the seven OSI layers in Gregorian chant. Then you'll know you've Gotten It.

http://www.softlab.ntua.gr/facilitie...q-2.html#ss2.8

Q: Why does it take so long to detect that the peer died?

A: ...
The approach taken by most application protocols currently in use on the Internet (e.g. FTP, SMTP etc.) is to implement read timeouts on the server end; the server simply gives up on the client if no requests are received in a given time period (often of the order of 15 minutes).

Protocols where the connection is maintained even if idle for long periods have two choices:

1. use SO_KEEPALIVE
2. use a higher-level keepalive mechanism (such as sending a null request to the server every so often).
'Hope that helps .. PSM

Lobinho 08-06-2010 05:23 PM

Thanks for your reply paulsm4!

I read the links (and a lot of other links), but no practical solution yet. My project is like a data logger, so I just need that my client connect, receive some data from me, disconnect, connect again, receive data... and repeat this procedure when the client need to get some information (that means any time of day).

I'll try to do some tests here... but I'm losing my hope of find a simple solution :/

Thanks anyway. :D

paulsm4 08-06-2010 05:52 PM

Hi -

It sounds like everything you're trying to do, sockets already does for you! Specifically:

1. You start your server.
He sets himself up, and starts listening for client requests.

2. You start your client. He wants to exchange information with the server.

3. The client "connects".
At that point, a NEW socket is created on the server, specifically for THAT connection.
Your server can do whatever he wants with that connection to service it - including start a new thread, or fork off a new process.

4. At some point, the server goes back and resumes listening for new connection requests. If he forked a new process, he can do it immediately (both the "server" process and the "service handler" process can run at the same time). Otherwise, you can't read any new connections until you're done servicing the current one (which is often perfectly acceptable).

5. Either way, at some point: the client is done, and he closes his socket. The server is done, and he closes his socket. The connection closes, and everybody's happy.

It's usually really as simple as that!

One other link that might help: Beej's Guide:

http://beej.us/guide/bgnet/

Your .. PSM

Lobinho 08-09-2010 04:27 PM

Hi paulsm4,

Thanks again for your help. The problem is that I don't know when the client finished his job, moreover, the server will send some status to the client like a 'hey client, someone pushed my button here!' (obviously, when the client is connected) in a kind of 'online communication'. Unfortunately, I can't use poll :/.

I solved this issue by using select function inside a thread.

http://linux.die.net/man/2/select

dwhitney67 08-09-2010 09:22 PM

Quote:

Originally Posted by Lobinho (Post 4061052)
Hi paulsm4,

Thanks again for your help. The problem is that I don't know when the client finished his job, moreover, the server will send some status to the client like a 'hey client, someone pushed my button here!' (obviously, when the client is connected) in a kind of 'online communication'. Unfortunately, I can't use poll :/.

I solved this issue by using select function inside a thread.

http://linux.die.net/man/2/select

When the client performs some activity (ie writes or disconnects), the server can be setup to be notified of such. Look into using select(). When select() indicates that there is activity on the client socket, you should attempt to read from the socket. If recv() returns a status of zero (bytes), then that is the clue that the client disconnected.

Perhaps the following code will serve as a guide:
Code:

// open listen socket
...

// bind socket
...

// listen on socket
...

// accept connection(s)
while (true) {
  int client_sock = accept(listen_sock, 0, 0);

  if (client_sock > 0) {
      handleClient(client_sock);
  }
}


void handleClient(int sd)
{
  fd_set read_sd;
  FD_ZERO(&read_sd);
  FD_SET(sd, &read_sd);

  while (true) {
      fd_set rsd = read_sd;

      int sel = select(sd + 1, &rsd, 0, 0, 0);

      if (sel > 0) {
        // client has performed some activity (sent data or disconnected?)

        char buf[1024] = {0};

        int bytes = recv(sd, buf, sizeof(buf), 0);

        if (bytes > 0) {
            // got data from the client.
        }
        else if (bytes == 0) {
            // client disconnected.
            break;
        }
        else {
            // error receiving data from client. You may want to break from
            // while-loop here as well.
        }
      }
      else if (sel < 0) {
        // grave error occurred.
        break;
      }
  }

  close(sd);
}


P.S. The usage of select() is not paramount; the main thing is to examine the return value from recv() to determine if the client sent data or has disconnected. In the example above, select() will block until there is activity on the socket. If this is not desirable, then a timeout period (struct timeval) should be provided at the 5th arg to select(). Otherwise, calling recv() directly on a blocking socket will result in the app being blocked until the client performs some action.

Lobinho 08-10-2010 02:28 PM

Thanks dwhitney67,

My current code is similar to your suggestion.
I didn't know the timeout parameter, it will be very useful.


All times are GMT -5. The time now is 11:34 AM.