- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Основы программирования в Linux - Нейл Мэтью
Шрифт:
Интервал:
Закладка:
if (fd == server_sockfd) {
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr*)&client_address, &client_len);
FD_SET(client_sockfd, &readfds);
printf("adding client on fd %dn", client_sockfd);
}
Если активен не сервер, значит, активность проявляет клиент. Если получен close, клиент исчезает, и можно удалить его из множества дескрипторов. В противном случае вы "обслуживаете" клиента, как и в предыдущих примерах.
else {
ioctl(fd, FIONREAD, &nread);
if (nread == 0) {
close(fd);
FD_CLR(fd, &readfds);
printf("removing client on fd %dn", fd);
} else {
read(fd, &ch, 1);
sleep(5);
printf("serving client on fd %dn", fd);
ch++;
write(fd, &ch, 1);
}
}
}
}
}
}
ПримечаниеВ реальную программу было бы неплохо вставить переменную, содержащую наибольший подключенный номер fd (необязательно самый последний подключенный номер fd). Это помешает просмотру в цикле тысяч номеров fd, которые даже не подсоединены и потенциально не могут быть готовы к чтению. Мы пропустили этот фрагмент кода для краткости и простоты примера.
При запуске этой версии сервера многочисленные клиенты будут обрабатываться последовательно в единственном процессе.
$ ./server5 &
[1] 26686
server waiting
$ ./client3 & ./client3 & ./client3 & ps x
[2] 26689
[3] 26690
adding client on fd 4
server waiting
[4] 26691
PID TTY STAT TIME COMMAND
26686 pts/1 S 0:00 ./server5
26689 pts/1 S 0:00 ./client3
26690 pts/1 S 0:00 ./client3
26691 pts/1 S 0:00 ./client3
26692 pts/1 R+ 0:00 ps x
$ serving client on fd 4
server waiting
adding client on fd 5
server waiting
adding client on fd 6
char from server = В
serving client on fd 5
server waiting
removing client on fd 4
char from server = В
serving client on fd 6
server waiting
removing client on fd 5
server waiting
char from server = В
removing client on fd 6
server waiting
[2] Done ./client3
[3]- Done ./client3
[4]+ Done ./client3
Для полноты аналогии, упомянутой в начале главы, в табл. 15.5 приведены параллели между соединениями на базе сокетов и телефонными переговорами.
Таблица 15.5
Телефон Сетевые сокеты Звонок в компанию по номеру 555-0828 Подключение к IP-адресу 127.0.0.1 Ответ на звонок секретаря приемной Установка соединения с remote host Просьба соединить с финансовым отделом. Маршрутизация с помощью заданного порта (9734) Ответ на звонок администратора финансового отдела Вызов select вернул управление серверу Звонок переадресован свободному менеджеру по работе с корпоративными заказчиками Сервер вызывает accept, создавая новый сокет на добавочный номер 456Дейтаграммы
В этой главе мы сосредоточились на программировании приложений, поддерживающих связь со своими клиентами с помощью TCP-соединений на базе сокетов. Существуют ситуации, в которых затраты на установку и поддержку соединения с помощью сокетов излишни.
Хорошим примером может служить сервис daytime, использованный ранее в программе getdate.c. Вы создаете сокет, выполняете соединение, читаете единственный ответ и разрываете соединение. Столько операций для простого получения даты!
Сервис daytime так же доступен с помощью UDP-соединений, применяющих дейтаграммы. Для того чтобы воспользоваться им, просто пошлите сервису одну дейтаграмму и получите в ответ единственную дейтаграмму, содержащую дату и время. Все просто.
Сервисы, предоставляемые по UDP-протоколу, применяются в тех случаях, когда клиенту нужно создать короткий запрос к серверу, и он ожидает единственный короткий ответ. Если стоимость времени процессора достаточно низкая, сервер способен обеспечить такой сервис, обрабатывая запросы клиентов по одному и разрешая операционной системе хранить очередь входящих запросов. Такой подход упрощает программирование сервера.
Поскольку UDP — не дающий гарантий сервис, вы можете столкнуться с потерей вашей дейтаграммы или ответа сервера. Если данные важны для вас, возможно, придется тщательно программировать ваших UDP-клиентов, проверяя ошибки и при необходимости повторяя попытки. На практике в локальных сетях UDP-дейтаграммы очень надежны.
Для доступа к сервису, обеспечиваемому UDP-протоколом, вам следует применять системные вызовы socket и close, но вместо использования вызовов read и write для сокета вы применяете два системных вызова, характерных для дейтаграмм: sendto и recvfrom.
Далее приведена модифицированная версия программы getdate.c, которая получает дату с помощью сервиса UDP-дейтаграмм. Изменения по сравнению с предыдущей версией выделены цветом.
/* Начните с обычных include и объявлений. */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char *host;
int sockfd;
int len, result;
struct sockaddr_in address;
struct hostent *hostinfo;
struct servent *servinfo;
char buffer[128];
if (argc == 1) host = "localhost";
else host = argv[1];
/* Ищет адрес хоста и сообщает об ошибке, если не находит. */
hostinfo = gethostbyname(host);
if (!hostinfo) {
fprintf(stderr, "no host: %sn", host);
exit(1);
}
/* Проверяет наличие на компьютере сервиса daytime. */
servinfo = getservbyname("daytime", "udp");
if (!servinfo) {
fprintf(stderr, "no daytime servicen");
exit(1);
}
printf("daytime port is %dn", ntohs(servinfo->s_port));
/* Создает UDP-сокет. */
sockfd = socket(AF_INEТ, SOCK_DGRAM, 0);
/* Формирует адрес для использования в вызовах sendto/recvfrom... */
address.sin_family = AF_INET;
address.sin_port = servinfo->s_port;
address.sin_addr = *(struct in_addr*)*hostinfo->h_addr_list;
len = sizeof(address);
result = sendto(sockfd, buffer, 1, 0, (struct sockaddr *)&address, len);
result = recvfrom(sockfd, buffer, sizeof(buffer), 0,
(struct sockaddr *)&address, &len);
buffer [result] = ' ';
printf("read %d bytes: %s", result, buffer);
close(sockfd);
exit(0);
}
Как видите, необходимы лишь незначительные изменения. Как и раньше, вы ищете сервис daytime с помощью вызова getservbyname, но задаете дейтаграммный сервис, запрашивая UDP-протокол. Дейтаграммный сокет создается с помощью вызова socket с параметром SOCK_DGRAM. Адрес назначения задается, как и раньше, но теперь вместо чтения из сокета вы должны послать дейтаграмму.
Поскольку вы не устанавливаете явное соединение с сервисами на базе UDP, у вас должен быть способ оповещения сервера о том, что вы хотите получить ответ. В данном случае вы посылаете дейтаграмму (в нашем примере вы отправляете один байт из буфера, в который вы хотите получить ответ) сервису и он посылает в ответ дату и время.
Системный вызов sendto отправляет дейтаграмму из буфера на сокет, используя адрес сокета и длину адреса. У этого вызова фактически следующий прототип:
int sendto(int sockfd, void *buffer, size_t len, int flags,
struct sockaddr *to, socklen_t tolen);
В случае обычного применения параметр flags можно оставлять нулевым.
Системный вызов recvfrom ожидает дейтаграмму в соединении сокета с заданным адресом и помещает ее в буфер. У этого вызова следующий прототип:
int recvfrom(int sockfd, void *buffer, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
И снова в случае обычного применения параметр flags можно оставлять нулевым.
Для упрощения примера мы пропустили обработку ошибок. Оба вызова, sendto и recvfrom, в случае возникновения ошибки вернут -1 и присвоят переменной errno соответствующее значение. Возможные ошибки перечислены в табл. 15.6.
Таблица 15.6

