Читаем Linux API. Исчерпывающее руководство полностью

continue; /* В случае ошибки пробуем следующий адрес */

 if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval,

sizeof(optval)) == -1)

errExit("setsockopt");

 if (bind(lfd, rp->ai_addr, rp->ai_addrlen) == 0)

break; /* Успех */

/* Вызов bind() завершился неудачно; закрываем этот сокет и пробуем следующий адрес */

close(lfd);

}

if (rp == NULL)

fatal("Could not bind socket to any address");

if (listen(lfd, BACKLOG) == -1)

errExit("listen");

freeaddrinfo(result);

for (;;) { /* Обслуживаем клиентов итерационно */

/* Принимаем соединение со стороны клиента и получаем его адрес */

addrlen = sizeof(struct sockaddr_storage);

 cfd = accept(lfd, (struct sockaddr *) &claddr, &addrlen);

if (cfd == -1) {

errMsg("accept");

continue;

}

 if (getnameinfo((struct sockaddr *) &claddr, addrlen,

host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)

snprintf(addrStr, ADDRSTRLEN, "(%s, %s)", host, service);

else

snprintf(addrStr, ADDRSTRLEN, "(?UNKNOWN?)");

printf("Connection from %s\n", addrStr);

/* Считываем запрос клиента, возвращаем в ответ элемент последовательности */

 if (readLine(cfd, reqLenStr, INT_LEN) <= 0) {

close(cfd);

continue; /* Ошибка при чтении; пропускаем запрос */

}

 reqLen = atoi(reqLenStr);

if (reqLen <= 0) { /* Отслеживаем клиентов, которые ведут себя некорректно */

close(cfd);

continue; /* Некорректный запрос; пропускаем его */

}

 snprintf(seqNumStr, INT_LEN, "%d\n", seqNum);

if (write(cfd, seqNumStr, strlen(seqNumStr))!= strlen(seqNumStr))

fprintf(stderr, "Error on write");

 seqNum += reqLen; /* Обновляем элемент последовательности */

if (close(cfd) == -1) /* Закрываем соединение */

errMsg("close");

}

}

sockets/is_seqnum_sv.c

Клиентская программа

Клиентская программа, показанная в листинге 55.7, принимает два аргумента. Первый, обозначающий имя узла, на котором работает сервер, является обязательным. Второй аргумент, определяющий длину последовательности, запрашиваемой клиентом, можно пропустить. По умолчанию длина равна 1. Клиент выполняет следующие шаги.

• Вызывает функцию getaddrinfo(), чтобы получить список структур с адресами, подходящими для подключения к TCP-серверу, привязанному к заданному узлу . В качестве номера порта клиент указывает значение PORT_NUM.

• Входит в цикл , который перебирает адреса, полученные в предыдущем шаге, пока не найдет тот, что позволяет успешно создать сокет и подключиться с его помощью к серверу . Так как клиент не привязывает свой сокет, в результате вызова connect() ядро автоматически назначает ему динамический порт.

• Отправляет целое число, обозначающее длину нужной клиенту последовательности . Это число передается в строковом виде с символом новой строки в конце.

• Считывает номер последовательности, переданный сервером (который тоже имеет строковый формат и символ новой строки в конце) , и направляет его в стандартный вывод .

Запустив сервер и клиент на одном и том же компьютере, мы увидим следующее:

$ ./is_seqnum_sv &

[1] 4075

$ ./is_seqnum_cl localhost Клиент 1: запрашивает один элемент

последовательности

Connection from (localhost, 33273) Сервер выводит адрес и порт клиента

Sequence number: 0 Клиент выводит элемент

последовательности

$ ./is_seqnum_cl localhost 10 Клиент 2: запрашивает десять элементов

последовательности

Connection from (localhost, 33274)

Sequence number: 1

$ ./is_seqnum_cl localhost Клиент 3: запрашивает один элемент

последовательности

Connection from (localhost, 33275)

Sequence number: 11

Теперь покажем, как с помощью утилиты telnet можно выполнить отладку этого приложения:

$ telnet localhost 50000 Наш сервер использует этот номер порта

Пустая строка, которую выводит telnet

Trying 127.0..0.1…

Connection from (localhost, 33276)

Connected to localhost.

Escape character is '^]'.

Вводим длину запрашиваемой последовательности

12 telnet выводит элемент последовательности

Connection closed by foreign host. и обнаруживает, что сервер закрыл соединение

В сессии командной строки, приведенной выше, можно видеть, что ядро циклически перебирает номера динамических портов (другие реализации демонстрируют похожее поведение). В Linux такое поведение является результатом оптимизации, призванной сократить количество запросов к таблице ядра, хранящей локальные привязки сокетов. При достижении максимального значения ядро опять начинает выделять доступные номера, начиная с наименьшего элемента диапазона (который, в свою очередь, определяется в файле /proc/sys/net/ipv4/ip_local_port_range, доступном только в Linux).

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

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

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных