LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-06-2008, 07:44 PM   #1
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
in need of a 'select' break with a closed socket


I'm working on a server-like program which calls select in a loop using multiple stream sockets. All descriptors in the program are non-blocking, so select and a pthread_cond_wait somewhere else are the only blocking points I have.

I'm having a "problem" when a connected client exits and the cooresponding socket descriptor on the server isn't the first in the select list. The select call doesn't break until another descriptor has data ready or until the first descriptor's other end closes. In other words, the only break for an unreadable socket happens when that socket is the first in the list. This keeps the descriptor hanging, but more importantly, keeps the program from accurately updating the status of what's connected.

As an example:
  • client X connects to the server (placed 1st with FD_SET)
  • client Y connects to the server (placed 2nd with FD_SET)
  • client Z connects to the server (placed 3rd with FD_SET)
  • ...
  • client Y exits and implicitly closes it's connections
  • the socket for Y is still a part of the select list until either X or Z send data or X exits
I experimented with a timeout for select, but I'd be better off using while (read(...) < 0); or something similarly attrocious because of its processor intensity.

I get the feeling I'm partially lucky to get what I am getting due to undefined behavior. The main goal is to have a blocked server except for when something is happening. Thanks.
ta0kira

PS The exit happens during the blocked select call. I haven't been able to create a situation where the exit happens between the select calls since.

Last edited by ta0kira; 01-06-2008 at 07:47 PM.
 
Old 01-07-2008, 03:41 PM   #2
Mara
Moderator
 
Registered: Feb 2002
Location: Grenoble
Distribution: Debian
Posts: 9,696

Rep: Reputation: 232Reputation: 232Reputation: 232
Which set do you check when waiting for connection close?
 
Old 01-07-2008, 11:38 PM   #3
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Quote:
Originally Posted by ta0kira View Post
... I experimented with a timeout for select, but I'd be better off using while (read(...) < 0); or something similarly attrocious because of its processor intensity.
I don't quite understand what is atrocious about using a timeout with select(). Doesn't your server thread have to check if there are other clients connecting? How will it do so if it is suspended while waiting for activity from an existing client?

When a client disconnects, select() reports activity with the client's socket. At this point, the server will not know what type of activity has occurred until a read() is performed. If the read() operation returns a value less than zero, then you know that the client has disconnected.

Here's a code snippet of a multi-threaded server I worked on many years ago that handles data incoming from multiple clients. Note that client connections where handled in a separate thread.

PHP Code:
  while (!stop_requested())
  {
    
//   Setup file descriptor list for select call
    //
    
struct timeval timeout = {10};  // one second
    
fd_set         readSet;
    const 
uint32_t nfds m_clientList.getClientSet(read_set);


    
//   Check if there is any data traffic to be read on any of the
    //   file descriptors.
    //
    
if (select(nfds+1, &readSetNULLNULL, &timeout) == 0)
    {
      
dbg[*this] << "select timed out" << el;
      continue;
    }

    
// The code below to determine the client was actually done in a
    // a mutex-protected method within the m_clientList object.  I've
    // shown it here just to show the gist of what needed to get the
    // handle to the client object (if any).
    //
    
Client *client NULL;

    for (
Iterator it m_clientList.begin(); it != m_clientList.end(); ++it)
    {
      if (
FD_ISSET(it->first, &readSet))
      {
        
client it->second;
      }
    }

    if (
client == NULL)
    {
      
dbg[*this] << "Client object could not be found" << el;
      continue;
    }

    
// Client is known.
    //
    
bool newMsgAvailable true;

    while (
newMsgAvailable == true)
    {
      
char    msg[MsgAPI::MAX_MSGLEN] = {NULL};
      
size_t  msgSize client->getNextMsg(msgsizeof msg);  // read() done in here

      
switch (msgSize)
      {
        case 
Client::NO_NEW_MSG:
            
dbg[*this] << "No new message received" << el;
            
newMsgAvailable false;
            break;

        case 
Client::MSG_TOO_LARGE:
        case 
Client::CLIENT_DISCONNECTED:
            
dbg[*this] << "Msg Too Large or Client Disconnected" << el;
            
m_clientList.removeClient(client);
            
newMsgAvailable false;
            break;

        default:
            
dbg[*this] << "Got a message" << el;
            ...
            break;
      }
    } 
Let me know if you have any further questions or comments.
 
Old 01-08-2008, 10:22 AM   #4
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Original Poster
Rep: Reputation: Disabled
When I used a timeout with select my processor activity jumped to over 90%, whereas keeping it indefinite allowed it to stay near idle.

shutdown on client exit seems to be working. I've been checking the read set. Thanks.
ta0kira
 
Old 01-08-2008, 11:05 AM   #5
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Your processor shouldn't have jumped to 90% because of the select(). It was probably something else on your system (or your application, if it is multithreaded) that is causing the issue.

Compile and run the following program, and verify if indeed the process is taking up a substantial amount of CPU time.

PHP Code:
#include <ctime>
#include <cstdlib>
#include <unistd.h>

int mainint argcchar **argv )
{
  
int seconds = (argc atoi(argv[1]) : 30);
  
int usecs   = (argc atoi(argv[2]) : );

  
struct timeval tv;
  
tv.tv_sec  seconds;
  
tv.tv_usec usecs;

  
// perform delay
  
select0000, &tv );

  return 
0;

 
Old 01-08-2008, 03:42 PM   #6
Mara
Moderator
 
Registered: Feb 2002
Location: Grenoble
Distribution: Debian
Posts: 9,696

Rep: Reputation: 232Reputation: 232Reputation: 232
In fact, the connection is closed if read returns less or EQUAL to zero. Quite an important condition.

I guess the high processor usage was because of the not handled the closure and select was not blocking inside, just returning.
 
Old 01-10-2008, 04:35 PM   #7
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Original Poster
Rep: Reputation: Disabled
Actually, the place where I used select with a timeout was for a bound local socket. The socket was open the entire time, and literally the only change was the addition of a 100ms timeout. Non-blocking accept with a 100ms retry in its place kept processor useage low, so, it wasn't the loop code. The matter of having a closed socket is a different one, though. It did take place within a pthread, so that might be the problem. I'll try to duplicate both conditions: the timeout and the non-first descriptor.

The way I do test for a closed socket is to take the result of select (as long as errno isn't EINTR) and try to read each descriptor (non-blocking.) If I get a 0 read then I close it and remove it from the list. shutdown does seem to force select to break, though.
ta0kira
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
checking if a connection is closed using select(); Thinking Programming 7 12-13-2005 03:19 PM
how do i know if the connection is closed using a nonblocking socket? Thinking Programming 2 10-06-2005 08:53 AM
Select() did not select my socket thvo Programming 1 05-08-2005 12:20 AM
how to find out if a nonblocking socket is closed jwstric2 Programming 3 04-03-2005 10:14 AM
tightVNC - RFB socket closed abapdr Linux - General 0 05-26-2004 03:26 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:00 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration