Литмир - Электронная Библиотека
Содержание  
A
A

1. Начните как обычно с директив

include
и объявлений, а затем инициализируйте
inputs
для обработки ввода с клавиатуры:

#include <sys/types.h>

#include <sys/time.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <stdlib.h>

int main() {

 char buffer[128];

 int result, nread;

 fd_set inputs, testfds;

 struct timeval timeout;

 FD_ZERO(&inputs);

 FD_SET(0, &inputs);

2. Подождите ввод из файла stdin в течение максимум 2,5 секунд:

 while(1) {

  testfds = inputs;

  timeout.tv_sec = 2;

  timeout.tv_usec = 500000;

  result = select(FD_SETSIZE, &testfds, (fd_set *)NULL,

   (fd_set*)NULL, &timeout);

3. Спустя это время проверьте

result
. Если ввода не было, программа выполнит цикл еще раз. Если в нем возникла ошибка, программа завершается:

  switch(result) {

  case 0:

   printf("timeout\n");

   break;

  case -1:

   perror("select");

   exit(1);

4. Если во время ожидания у вас наблюдаются некоторые действия, связанные с файловым дескриптором, читайте ввод из stdin и выводите его при каждом получении символа EOL (конец строки), до нажатой комбинации клавиш <Ctrl>+<D>:

  default:

   if (FD_ISSET(0, &amp;testfds)) {

    ioctl(0, FIONREAD, &amp;nread);

    if (nread == 0) {

     printf(&quot;keyboard done\n&quot;);

     exit(0);

    }

    nread = read(0, buffer, nread);

    buffer[nread] = 0;

    printf(&quot;read %d from keyboard: %s&quot;, nread, buffer);

   }

   break;

  }

 }

}

Во время выполнения эта программа каждые две с половиной секунды выводит строку

timeout
. Если вы набираете данные на клавиатуре, она читает файл стандартного ввода и отображает то, что было набрано. В большинстве командных оболочек ввод направляется в программу при нажатии пользователем клавиши <Enter> (или <Return>) или клавиш управляющей последовательности, поэтому программа будет отображать ввод каждый раз, когда вы нажимаете клавишу <Enter>. Учтите, что сама клавиша <Enter> тоже читается и обрабатывается как любой другой символ (попробуйте выполнить ввод без нажатия клавиши, введя ряд символов, за которыми следует комбинация <Ctrl>+<D>).

$ <b>./select</b>

timeout

<b>hello</b>

read 6 from keyboard: hello

<b>fred</b>

read 5 from keyboard: fred

timeout

<b>^D</b>

keyboard done

$

Как это работает

Программа применяет вызов

select
для проверки состояния стандартного ввода. За счет корректировки значения времени ожидания программа каждые 2,5 секунды выводит сообщение об истечении времени ожидания. О нем свидетельствует возвращение 0 функцией
select
. При достижении конца файла дескриптор стандартного ввода помечается флагом как готовый к вводу, но при этом нет символов, предназначенных для считывания.

Множественные клиенты

Ваша простая серверная программа может выиграть от применения

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

Сервер может применять функцию

select
одновременно к сокету, ожидающему запросы на подключение, и к сокетам клиентских соединений. Как только активность зафиксирована, можно использовать макрос
FD_ISSET
для проверки в цикле всех возможных файловых дескрипторов и выявления активных среди них.

Если сокет, ожидающий запросов на подключение, готов к вводу, это означает, что клиент пытается подсоединиться, и вы можете вызывать функцию

accept
без риска блокировки. Если клиентский дескриптор указывает на готовность, это означает, что есть запрос клиента, ждущий, что вы сможете прочесть и обработать его. Чтение 0 байтов означает, что клиентский процесс завершился, и вы можете закрыть сокет и удалить его из множества своих дескрипторов.

Выполните упражнение 15.9.

Упражнение 15.9. Улучшенное клиент-серверное приложение

1. В финальный пример программы server5.с вы включите заголовочные файлы sys/time.h и sys/ioctl.h вместо signal.h, использованного в предыдущей программе, и объявите несколько дополнительных переменных для работы с вызовом

select
:

#include &lt;sys/types.h&gt;

#include &lt;sys/socket.h&gt;

#include &lt;stdio.h&gt;

#include &lt;netinet/in.h&gt;

#include &lt;sys/time.h&gt;

#include &lt;sys/ioctl.h&gt;

#include &lt;unistd.h&gt;

#include &lt;stdlib.h&gt;

275
{"b":"285844","o":1}