5

I'm trying to wrap my head around calling select on sockets and I can't understand what I'm doing wrong.

setup_server_socket calls bind and listen and sets the socket to nonblocking mode.

The following code blocks on the select call it seems, not moving forward to FD_ISSET. I tried connecting a client and it seems to succeed but select never returns anything.

What's the proper way to do this?

...
int listenfd = setup_server_socket( serverPort );

if( -1 == listenfd )
    return 1;

fd_set read_fds;
FD_ZERO(&read_fds);
int fdmax = listenfd;


// loop forever
while( 1 )
{
    if (select(fdmax+1, &read_fds, NULL,NULL,NULL) == -1){
        perror("select");
        exit(4);
    }

    for (int i = 0; i<= fdmax; i++){
        printf("Testing: %d, %d\n", i, FD_ISSET(i,&read_fds));

    }return 0;
...
cadaniluk
  • 15,027
  • 2
  • 39
  • 67
Benjamin Lindqvist
  • 4,300
  • 3
  • 18
  • 19
  • 1
    From the fine manual: `... If time‐ out is NULL (no timeout), select() can block indefinitely. ...` BTW: a -1 return from select() is *not an error* – joop Sep 22 '15 at 08:50
  • Sure but just because it CAN doesn't mean it should... the problem I was having was that FD_ISSET never returned anything, despite clients being connected. But it was because I didn't use FD_SET first. – Benjamin Lindqvist Sep 22 '15 at 09:03
  • 1
    Also: you have to reinitialize read_fds *every time* before calling select() (select alters the fd_sets ) . Mostly this is done by copying from yet another fd_set. – joop Sep 22 '15 at 09:10
  • Sweet, I think I'm starting to get it now. – Benjamin Lindqvist Sep 22 '15 at 09:12
  • 1
    And, after a -1 return from select, *thou should check errno* , especially EINTR/EAGAIN/EWOULDBLOCK should not be treated as error. – joop Sep 22 '15 at 09:20

2 Answers2

10

Read several times syscalls(2), select(2), select_tut(2), poll(2), errno(3) (BTW, you should prefer poll(2) to the obsolete select, which don't handle file descriptors bigger than __FD_SETSIZE, i.e. 1024 on my Linux/Debian/x86-64 system).

Then:

fd_set read_fds;
FD_ZERO(&read_fds);
int fdmax = listenfd;
FD_SET(listenfd, &read_fds);

should go inside the while(1) loop, before calling select. BTW, I recommend using poll instead of select

Read also about the C10k problem

Don't forget that select is changing its given fd_set-s (and usually wants them to be non-empty)...

Perhaps use strace(1) and gdb(1). If you compile with GCC, invoke it as gcc -Wall -Wextra -g to get more warnings and debug info. If you compile your C code with Clang, consider using the Clang Static Analyzer.

Read also Advanced Linux Programming (it is a free book that you could also read on paper, or download from several other places, e.g. this etc...)

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
2

here is one (trimmed) example of using select()

INT32    selectStatus;                                 /* select() return code */

char     tempreport[ 256 ] = {'\0'};

struct   timeval tv;

fd_set   fdread;
//fd_set   fdwrite;
//fd_set   fdexcep;



// note:
//  must try to read report until no report available 
// so have latest report in buffer
do
{
    /* Note: timeout must be (re)set every time before call to select() */
    tv.tv_sec = 1;
    tv.tv_usec = 0;


    FD_ZERO(&fdread);
    FD_SET( FD, &fdread );

    selectStatus = select(FD+1, &fdread, NULL, NULL, &tv);

    switch( selectStatus )
    {
        case -1:
            ....
            break;

        case 0:
            // timeout, I.E. nothing to read
            ....
            break;

        default: /* available to read */

            memset(tempreport, 0x00, sizeof(tempreport) );
            readStatus = read_UDP_socket( FD, tempreport, sizeof(tempreport), &readCount );

            break;
    } // end switch( selectStatus )
} while( (0 < selectStatus)&&(eRS_Success == readStatus ) );
 // exit loop on select timeout or select error or read failure

notes:

eRS_Success is an entry from an enum used for various return codes
read_UDP_socket() is a local function
user3629249
  • 16,402
  • 1
  • 16
  • 17