2008-09-30 2 views
3

UPDATE: Я обновил код и описание проблемы, чтобы отразить мои изменения.Что не так с этим примером _popen/select?

Теперь я знаю, что я пытаюсь выполнить операцию сокета на несете. или что мой fd_set не действует так:

select возвращает -1 и WSAGetLastError() возвращается 10038.

Но я не могу показаться, чтобы выяснить, что это такое. Платформа - это Windows. Я не размещал часть WSAStartup.

int loop = 0; 
FILE *output 

int main() 
{ 
    fd_set fd; 
    output = _popen("tail -f test.txt","r"); 

    while(forceExit == 0) 
    { 
     FD_ZERO(&fd); 
     FD_SET(_fileno(output),&fd); 

     int returncode = select(_fileno(output)+1,&fd,NULL,NULL,NULL); 
     if(returncode == 0) 
     { 
      printf("timed out"); 
     } 
     else if (returncode < 0) 
     { 
      printf("returncode: %d\n",returncode); 
      printf("Last Error: %d\n",WSAGetLastError()); 
     } 
     else 
     { 
      if(FD_ISSET(_fileno(output),&fd)) 
      { 
       if(fgets(buff, sizeof(buff), output) != NULL) 
       {    
        printf("Output: %s\n", buff); 
       } 
      } 
      else 
      { 
       printf("."); 
      } 
     } 
     Sleep(500); 
    } 
    return 0; 
} 

Новый результат - это, конечно, распечатка кода возврата и последней ошибки.

ответ

0

Первый аргумент для выбора должно быть самым высоким номером дескриптора файла в любом из трех наборов, плюс 1:

int select(int nfds, fd_set *readfds, fd_set *writefds, 
       fd_set *exceptfds, struct timeval *timeout); 

также:

if(FD_ISSET(filePointer,&exceptfds)) 
    { 
      printf("i have data\n"); 
    } 

Должно быть:

if(FD_ISSET(filePointer,&fd)) 
    { 
      printf("i have data\n"); 
    } 

Вы должны проверить код возврата из select().

Вам также необходимо сбросить fdsets каждый раз, когда вы вызываете select().

Вам не нужен таймаут, так как вы его не используете.

Edit:

Как видно на Windows, nfds игнорируется, но, вероятно, следует установить правильно, только поэтому код более компактен.

Если вы хотите использовать тайм-аут, вам нужно передать его в выберите вызов в качестве последнего аргумента:

// Reset fd, exceptfds, and timeout before each select()... 
int result = select(maxFDPlusOne, &fd, NULL, &exceptfds, &timeout); 

if (result == 0) 
{ 
    // timeout 
} 
else if (result < 0) 
{ 
    // error 
} 
else 
{ 
    // something happened 
    if (FD_ISSET(filePointer,&fd)) 
    { 
     // Need to read the data, otherwise you'll get notified each time. 
    } 
} 
+0

Ваш комментарий к первому аргументу для выбора, который необходимо установить правильно, верен для сокетов Berkeley. это не так в Windows. Параметр не используется (хотя он все равно должен быть правильно установлен IMHO!). Poseter не определил платформу, поэтому я подумал, что буду указывать на разные платформы. – Mark 2008-09-30 12:49:28

+0

платформа действительно Windows. Извините, что вы не публикуете, что – SinisterDex 2008-09-30 13:00:48

0

Первое, что я заметил, это не так, что вы вызываете FD_ISSET на ваших exceptfds в каждом условном. Я думаю, что вы хотите что-то вроде этого:

if (FD_ISSET(filePointer,&fd)) 
{ 
    printf("i have data\n"); 
} 
else .... 

исключения той области в избранном, как правило, используются для сообщения об ошибках или вне диапазона данных на сокете. Когда один из дескрипторов вашего исключения установлен, это не означает ошибки, а скорее некоторого «сообщения» (т. Е. Внеполосных данных). Я подозреваю, что для вашего приложения вы, вероятно, можете обойтись без добавления дескриптора файла внутри набора исключений. Если вы действительно хотите проверить наличие ошибок, вам нужно проверить возвращаемое значение select и сделать что-то, если оно вернет -1 (или SOCKET_ERROR в Windows). Я не уверен в вашей платформе, поэтому я не могу быть более конкретным относительно кода возврата.

3

У вас есть данные, готовые для чтения, но вы на самом деле ничего не читаете. Когда вы в следующий раз опросите дескриптор, данные все равно будут там. Слейте трубку, прежде чем продолжить опрос.

0
  1. select() первый аргумент является наивысшим Дескриптор номер файла в вашем наборе, плюс 1. (т.е.выход + 1)

    выбор (выход + 1, & fd, NULL, & exceptfds, NULL);

  2. Первый FD_ISSET(...) должен быть на fd_set fd.

    если (FD_ISSET (filePointer, & Fd))

  3. Ваш поток данных содержит данные, то вам необходимо прочитать этот поток данных. Используйте fgets (...) или аналогичные для чтения из источника данных.

    char buf [1024]; ... fgets (buf, sizeof (buf) * sizeof (char), output);

+0

изменений отражают ваши предложения, а затем выбрасывает -1. – SinisterDex 2008-09-30 14:16:25

1

Насколько я могу судить, анонимные трубы Windows не могут использоваться с неблокирующими вызовами, например select. Таким образом, в то время как ваш _popen и select код выглядит хорошо независимо, вы не можете присоединиться к ним вместе.

Here's a similar thread elsewhere.

Возможно, что вызов SetNamedPipeHandleState с флагом PIPE_NOWAIT может работать для вас, но MSDN больше, чем немного загадочный на эту тему.

Итак, я думаю, вам нужно посмотреть на другие способы достижения этого. Я предлагаю иметь чтение в отдельном потоке и использовать обычные блокирующие операции ввода-вывода.

1

Прежде всего, как указывали вы сами и другие, select() действителен только для сокетов под Windows. select() не работает в потоках, что и есть _popen(). Ошибка 10038 четко определяет это.

Я не понимаю, какова цель вашего примера. Если вы просто хотите, чтобы породить процесс и собрать это стандартный вывод, просто сделать это (который поступает непосредственно из _popen страницы MSDN):

int main(void) 
{ 

    char psBuffer[128]; 
    FILE *pPipe; 

    if((pPipe = _popen("tail -f test.txt", "rt")) == NULL) 
     exit(1); 

    /* Read pipe until end of file, or an error occurs. */ 

    while(fgets(psBuffer, 128, pPipe)) 
    { 
     printf(psBuffer); 
    } 


    /* Close pipe and print return value of pPipe. */ 
    if (feof(pPipe)) 
    { 
    printf("\nProcess returned %d\n", _pclose(pPipe)); 
    } 
    else 
    { 
    printf("Error: Failed to read the pipe to the end.\n"); 
    } 
} 

Вот так. Никакой выбор не требуется.

И я не уверен, как потоки помогут вам здесь, это просто усложнит вашу проблему.

Смежные вопросы