используя select для чтения из сокета и стандартного ввода

Я пишу программу чата на основе ncurses. Сначала я писал только сетевые вещи (без ncurses), и все работало нормально, но после добавления графики я не могу заставить клиентское приложение работать должным образом.

Основная проблема заключается в одновременном чтении из стандартного ввода и сокета. В версии без ncurses я использовал pthread, и он работал отлично. Увы, кажется, что pthread и ncurses не очень хорошо сочетаются друг с другом, поэтому мне пришлось искать другое решение. Я думал, что select() подойдет, но он по-прежнему читает только из стандартного ввода и полностью игнорирует сокет.

Вот весь код: код

Интересная часть:

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);
  }
}
}

Возможно, я не совсем понимаю, как работает select(), или, может быть, мне не нужно было подключаться() к сокету. Я здесь потерялся. Буду признателен за любую помощь! Спасибо.


person michauwilliam    schedule 28.04.2011    source источник
comment
вы знаете, что первое, что вы делаете, это выходите из программы, когда что-то приходит через сокет?   -  person Mario The Spoon    schedule 29.04.2011
comment
также не используйте FD_ZERO(0, используйте FD_SET(fileno(stdin),...   -  person Mario The Spoon    schedule 29.04.2011
comment
извините, выход был только для того, чтобы посмотреть, дойдет ли программа до этого момента. спасибо, что указали на это :P   -  person michauwilliam    schedule 29.04.2011
comment
Я думаю, вы ошибаетесь, думая, что ncurses и потоки несовместимы. Если у вас возникли проблемы, вы делаете что-то не так (например, пытаетесь манипулировать структурами данных curses из нескольких потоков одновременно).   -  person R.. GitHub STOP HELPING ICE    schedule 29.04.2011


Ответы (2)


Ваша проблема в select().
Первый параметр - это не количество файловых дескрипторов, которые вы передаете в read_fds, а самый высокий идентификатор сокета + 1.

Со страницы руководства:

В каждом наборе проверяются первые дескрипторы nfds; то есть проверяются дескрипторы от 0 до nfds-1 в наборах дескрипторов. (Пример: если вы установили два файловых дескриптора «4» и «17», nfds должен быть не «2», а «17 + 1» или «18».)

Итак, в вашем коде вместо «2» попробуйте передать «s+1».

person fabrizi0    schedule 28.04.2011
comment
спасибо, через FD_ISSET(s,&read_fds) не проходит, но буфер на экран все равно не выводит. Я думаю, сейчас это просто проблема ncurses, я постараюсь решить ее завтра. Спасибо :) Пс. если у вас есть идеи, почему он не печатает, дайте мне знать! - person michauwilliam; 29.04.2011
comment
я забыл о wrefresh после печати. проблема решена, спасибо - person michauwilliam; 29.04.2011

Вам нужно указать самый высокий файловый дескриптор для выбора:

if (select(s + 1,&read_fds,NULL,NULL,NULL) == -1){

select() необходимо знать количество файловых дескрипторов, которые он должен отслеживать.

person Richard Pennington    schedule 28.04.2011
comment
предполагается смотреть только 2 дескриптора - stdin и s - person michauwilliam; 29.04.2011
comment
Нет, число — это не количество файловых дескрипторов, оно больше, чем самый высокий файловый дескриптор. и s + 1 заведомо больше 2. - person Richard Pennington; 29.04.2011