Что не так с этим примером _popen / select?

Обновлено: Я обновил код и описание проблемы, чтобы отразить мои изменения.

Теперь я знаю, что пытаюсь выполнить операцию Socket на несокете. или что мой 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;
}

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
6 245
7

Ответы 7

Первым аргументом для выбора должен быть дескриптор файла с самым большим номером в любом из трех наборов плюс 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 ().

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

Редактировать:

Очевидно, в Windows nfds игнорируется, но, вероятно, должен быть установлен правильно, просто чтобы код был более переносимым.

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

// 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.
    }
}

Ваш комментарий о том, что первый аргумент для выбора должен быть установлен правильно, верен для сокетов Беркли. в Windows это не так. Параметр не используется (хотя его все равно надо правильно выставлять ИМХО!). Poseter не указал платформу, поэтому я подумал, что укажу на разные платформы.

Mark 30.09.2008 16:49

платформа действительно Windows. Извините за то, что не опубликовал это

SinisterDex 30.09.2008 17:00

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

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

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

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

  1. Первый аргумент select() - это дескриптор файла с наибольшим номером в вашем наборе плюс 1. (т.е. output + 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);

изменения отражают ваши предложения, однако select выдает -1.

SinisterDex 30.09.2008 18:16

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

Вот похожая ветка в другом месте.

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

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

хорошо .. я пробовал ваш подход безрезультатно. Ты хоть представляешь, как я могу добиться неблокирующей функции?

SinisterDex 30.09.2008 20:27

Вы не можете, AFAICT. Лучше всего просто использовать другой поток для чтения и выполнять обычную блокировку ввода-вывода.

Roddy 30.09.2008 21:08

поскольку select не работает, я использовал потоки, в частности _beginthread, _beginthreadex.

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

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

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

Вот и все. Выбор не требуется.

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

Другие вопросы по теме