Читаем UNIX: разработка сетевых приложений полностью

<p>5.7. Нормальное завершение</p>

На этом этапе соединение установлено, и все, что бы мы ни вводили на стороне клиента, отражается обратно.

linux % tcpcli01 127.0.0.1  эту строку мы показывали раньше

hello, world  наш ввод

hello, world отраженная сервером строка

good bye

good bye

^D  Ctrl+D - наш завершающий символ для обозначения конца файла

Мы вводим две строки, каждая из них отражается, затем мы вводим символ конца файла (EOF) Ctrl+D, который завершает работу клиента. Если мы сразу же выполним команду netstat, то увидим следующее:

linux % netstat -а | grep 9877

tcp 0 0 *:9877           *:*

tcp 0 0 local host:42758 localhost:9877

Клиентская часть соединения (локальный порт 42 758) входит в состояние TIME_WAIT (см. раздел 2.6), и прослушивающий сервер все еще ждет подключения другого клиента. (В этот раз мы передаем вывод netstatпрограмме grep, чтобы вывести только строки с заранее известным портом нашего сервера. Но при этом также удаляется строка заголовка.)

Перечислим этапы нормального завершения работы нашего клиента и сервера.

1. Когда мы набираем символ EOF, функция fgetsвозвращает пустой указатель, и функция str_cliвозвращает управление (см. листинг 5.4).

2. Когда функция str_cliвозвращает управление клиентской функции main(см. листинг 5.3), последняя завершает работу, вызывая функцию exit.

3. При завершении процесса выполняется закрытие всех открытых дескрипторов, так что клиентский сокет закрывается ядром. При этом серверу посылается сегмент FIN, на который TCP сервера отвечает сегментом ACK. Это первая половина последовательности завершения работы соединения TCP. На этом этапе сокет сервера находится в состоянии CLOSE_WAIT, а клиентский сокет — в состоянии FIN_WAIT_2 (см. рис. 2.4 и 2.5).

4. Когда TCP сервера получает сегмент FIN, дочерний процесс сервера находится в состоянии ожидания в вызове функции read(см. листинг 5.2), а затем функция readвозвращает нуль. Это заставляет функцию str_echoвернуть управление функции mainдочернего процесса сервера.

5. Дочерний процесс сервера завершается с помощью вызова функции exit(см. листинг 5.1).

6. Все открытые дескрипторы в дочернем процессе сервера закрываются. Закрытие присоединенного сокета дочерним процессом вызывает отправку двух последних сегментов завершения соединения TCP: FIN от сервера клиенту и ACK от клиента (см. рис. 2.5). На этом этапе соединение полностью завершается. Клиентский сокет входит в состояние TIME_WAIT.

7. Другая часть завершения процесса относится к сигналу SIGCHLD. Он отправляется родительскому процессу, когда завершается дочерний процесс. Это происходит и в нашем примере, но мы не перехватываем данный сигнал в коде, и по умолчанию он игнорируется. Дочерний процесс входит в состояние зомби (zombie). Мы можем проверить это с помощью команды ps.

linux % ps -t pts/6 -o pid,ppid,tty,stat,args,wchan

PID   PPID  TT    STAT COMMAND     WCHAN

22038 22036 pts/6 S    -bash       read_chan

17870 22038 pts/6 S    ./tcpserv01 wait_for_connect

19315 17870 pts/6 Z    [tcpserv01 

Теперь дочерний процесс находится в состоянии Z(зомби).

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

<p>5.8. Обработка сигналов POSIX</p>

Сигнал— это уведомление процесса о том, что произошло некое событие. Иногда сигналы называют программными прерываниями( software interrupts). Подразумевается, что процесс не знает заранее о том, когда придет сигнал.

Сигналы могут посылаться в следующих направлениях:

 одним процессом другому процессу (или самому себе);

 ядром процессу.

Сигнал SIGCHLD, упомянутый в конце предыдущего раздела, ядро посылает родительскому процессу при завершении дочернего.

Для каждого сигнала существует определенное действие( actionили dispositionхарактер). Действие, соответствующее сигналу, задается с помощью вызова функции sigaction(ее описание следует далее) и может быть выбрано тремя способами:

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
1001 совет по обустройству компьютера
1001 совет по обустройству компьютера

В книге собраны и обобщены советы по решению различных проблем, которые рано или поздно возникают при эксплуатации как экономичных нетбуков, так и современных настольных моделей. Все приведенные рецепты опробованы на практике и разбиты по темам: аппаратные средства персональных компьютеров, компьютерные сети и подключение к Интернету, установка, настройка и ремонт ОС Windows, работа в Интернете, защита от вирусов. Рассмотрены не только готовые решения внезапно возникающих проблем, но и ответы на многие вопросы, которые возникают еще до покупки компьютера. Приведен необходимый минимум технических сведений, позволяющий принять осознанное решение.Компакт-диск прилагается только к печатному изданию книги.

Юрий Всеволодович Ревич

Программирование, программы, базы данных / Интернет / Компьютерное «железо» / ОС и Сети / Программное обеспечение / Книги по IT