csocketsstdinncursesposix-select

using select to read from socket and stdin


I'm writing a ncurses based chat program. At first, I wrote just networking stuff (without ncurses) and everything worked fine, but after adding graphics I can't get the client app to work properly.

The main problem is reading from stdin and socket at the same time. In ncurses-less version I've used pthread and it worked like charm. Alas, it seems that pthread and ncurses don't go together very well, so I had to find another solution. I thought that select() would do, but it still only reads from stdin and completely ignores the socket.

Here is the whole code: code

The interesting part is:

char message[1024];
fd_set master;
fd_set read_fds;

FD_ZERO(&master);
FD_ZERO(&read_fds);

FD_SET(0,&master);
FD_SET(s,&master); // s is a socket descriptor
while(true){
read_fds = master;
if (select(2,&read_fds,NULL,NULL,NULL) == -1){
  perror("select:");
  exit(1);
}
// if there are any data ready to read from the socket
if (FD_ISSET(s, &read_fds)){
  n = read(s,buf,max);
  buf[n]=0;
  if(n<0)
  {
    printf("Blad odczytu z gniazdka");
    exit(1);
  } 
  mvwprintw(output_window,1,1,"%s\n",buf);
}
// if there is something in stdin
if (FD_ISSET(0, &read_fds)){
  getstr(message);
  move(CURS_Y++,CURS_X);
  if (CURS_Y == LINES-2){
    CURS_Y = 1;
  }
  n = write(s,message,strlen(message));
  if (n < 0){
    perror("writeThread:");
    exit(1);
  }
}
}

It's possible that I don't fully understand how select() works, or maybe I shouldn't have connect()ed the socket.. I'm lost here. I would appreciate any help! Thanks.


Solution

  • Your problem is in the select().
    The first parameter is not the number of file descriptors you are passing in read_fds, but it's the highest socket ID + 1.

    From the man page:

    The first nfds descriptors are checked in each set; i.e., the descriptors from 0 through nfds-1 in the descriptor sets are examined. (Example: If you have set two file descriptors "4" and "17", nfds should not be "2", but rather "17 + 1" or "18".)

    So in your code, instead of '2', try passing 's+1'.