Студопедия

КАТЕГОРИИ:

АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника


Проблема очередности действий и ее решение.




У нас имеется 2 дескриптора (как минимум). На одном из дескрипторов может ожидаться запрос на соединение нового клиента (accept). Если выполним accept, а никакого запроса на соединение не было, наша прога зависнет внутри этого вызова accept сколько угодно долго. В это время на любой из клиентских сокетов могут придти данные, требующие обработки, но пока мы внутри accept никакой обработки не будет. С другой стороны если произвести чтение с клиентского сокета есть риск что клиент не примет никаких данных в течение длительного времени. Все это время наша прога зависнет внутри вызова read.

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

Другое решение:

1. При написании сервер. проги можно создать отдельный процесс для обслуживания каждого клиента.

2. Если жалко, что созданные процессы много простаивают, можно сделать иначе: это решение на основе обслуживающих процессов. Наш главный процесс будет бОльшую часть времени находится в режиме accept. При принятии запроса от клиента наш процесс породит дочерний процесс для обслуживания клиента. После порождения родит процесс закрывает клиент. сокет, а дочерний процесс закрывает слушающий сокет, т.о. все обязанности по обслуживанию клиента ложатся на дочерний процесс. Все это время родит. процесс продолжает использовать слушающие обязанности вызывая accept.

Программа:

int ls;

struct sockaddr_cr addr;

ls = socket (AF_INET, SOCK_STREAM, 0);

if (ls==-1) {perror (“Error socket”);}

addr.sin_family = AF_INET;

addr.sin_port = htons (port);

addr.sin_addr.s_addr = INADDR_ANY;

// Заданная инструкция в системе принимает соединение по заданному порту при любом IP-адресе.

if (bind(ls, &addr, sizeof(addr))==-1) {perror (“error bind”);}

// Сформируем 3й параметр для accept – это будет размер адрес. структуры, куда будет записан адрес сокета с которого будет устанавливаться соединение.

for ( ; ; )

{

sock_len_t slen = sizeof (addr);

int cls = accept (ls, %addr, &slen);

if (fork()==0) {close(ls); anet(0);}

// Дальше работа с клиентом идет через сокет cls. Клиент пойдет с адреса, который хранится в addr.

// Дальше действия в родит. процессе:

close(cls);

// Далее проверим не завершился ли какой-нить дочерний процесс:

while (wait4(-1,NULL); //wait4 ждет любого заверш. процесса и убирает «зомби»

}

 

Мультиплексирование ввода/вывода. Событийно-управляемое программирование:

Когда порождение процесса по каждому клиент. соединению не приемлимо (например, сервер перегружен или между сеансами обслуживания разных клиентов происходит активное взаимодействие) надо оставить обслуживание всех клиентов в рамках одного процесса, но активное ожидание не приемлемо.

Пусть имеем некоторое количество типов событий, каждое из которых требует своей обработки. Многие систем. вызовы, предназначенные для обработки имеют след. свойство: будучи вызванными дл наступления события они это событие ожидают, блокируют вызвавший процесс и делают невозможным обработку других событий. Но возможно, что длительное время не наступит ни одного события =>надо исключить холостой расход процессорного времени, т.е. нужно иметь возможность отдать ОС процессорное время до наступления события.

Вызов select() позволяет обрабатывать события 3 типов:

1. Изменение состояния ФД (появление данных на чтение/запись на соединении; освобождение места в буфере; исключительная ситуация).

2. Истечение заданного количества времени с момента входа в вызов.

3. Получение процессом не игнорируемого сигнала.

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

readfds, writefds, exceptfds – множество ФД.

n – какое количетсво элементов в этих множествах является значимым.

(n = max_d+1 – рекомендуемое значение, где max_d – максимальный номер дескриптора)

timeout – параметр задает промежуток времени, спустя который требует вернуть управление процессу, даже если не произошло событие.

Тип fd_set можно представить как битовую строку, где каждому дескриптору соотв. 1 бит. Для работы с переменный такого типа UNIX предоставляет макросы:

FD_ZERO (fd_set *set);

FD_CLR (int fd, fd_set *set);

FD_SET (int fd, fd_set *set);

FD_ISSET (int fd, fd_set *set);

Тип timeval – структура которая имеет 2 поля (оба типа long int). 1ое поле – количество секунд, 2ое поле – количество vrc/

timeout = 5.3 c

struct timeval t

t.tv_sec = 5;

t.tv_usec = 300 000;

Вызов select() возвращает управление в следующих случаях:

1. Ошибка, возврат -1.

2. Получен не игнорируемый сигнал =>возврат тоже -1, далее надо сделать проверку errno = EINTR.

3. Истек timeout, возврат 0.

4. Примем данные на какой-либо из дескрипторов, а дескриптор определен в множестве readfds.

5. Какой-либо из дескрипторов writefds готов на записью

6. На каком-либо дескрипторе exceptfds возникло исключение.

В случаях 4,5,6 select возвращает количество дескрипторов изменивших статус, при этом все множество изменяется и в них остаются только те дескрипторы, которые изменили свой статус.

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

 

 


Поделиться:

Дата добавления: 2015-01-14; просмотров: 121; Мы поможем в написании вашей работы!; Нарушение авторских прав





lektsii.com - Лекции.Ком - 2014-2024 год. (0.007 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав
Главная страница Случайная страница Контакты