21.6.1 Вызовы в серверной программе TCP
21.6.1 Вызовы в серверной программе TCP
1. sockMain = socket (AF_INET, SOCK_STREAM, 0); Вызов socket имеет форму:
дескриптор_socket = socket(адрес_домена, тип_коммуникации, протокол)
Напомним, что интерфейс socket может использоваться для других видов коммуникаций, например XNS. AF_INET указывает на семейство адресов Интернета. SOCK_STREAM запрашивает socket TCP. Эта переменная должна иметь значение SOCK_DGRAM, чтобы создать socket UDP, a SOCK_RAW служит для непосредственного обращения к IP.
Не нужно явно определять никакую другую информацию протокола для TCP (или для UDP). Однако параметр protocol необходим для интерфейса с необработанными данными, а также для некоторых протоколов из других семейств, использующих socket.
2. struct sockaddr_in servAddr;
...
bzero((char *)&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = 0;
Программная структура servAddr используется для хранения адресной информации сервера. Вызов bzero() инициализирует servAddr, помещая нули во все параметры. Первая переменная в структуре servAddr указывает, что остальная часть значений содержит данные семейства адресов Интернета.
Следующая переменная хранит локальный IP-адрес сервера. Например, если сервер подключен к локальной сети Ethernet и к сети X.25, может потребоваться ограничить доступ клиентов через интерфейс Ethernet. В данной программе об этом можно не беспокоится. INADDR_ANY означает, что клиенты могут соединяться через любой интерфейс.
Функция htonl() имеет полное название host-to-network-long. Она применяется для преобразования 32-разрядных целых чисел локального компьютера в формат Интернета для 32-разрядного адреса IP. Стандарты Интернета предполагают представление целых чисел с наиболее значимым байтом слева. Такой стиль именуется Big Endian (стиль "тупоконечников"). Некоторые компьютеры хранят данные, располагая слева менее значимые байты, т.е. в стиле Little Endian ("остроконечников"). Если локальный компьютер использует стиль Big Endian, htonl() не будет выполнять никакой работы.
Если сервер взаимодействует через общеизвестный порт, номер этого порта нужно записать в следующую переменную. Поскольку мы хотим, чтобы операционная система сама присвоила порт для нашей тестовой программы, мы вводим нулевое значение.
3. bind(sockMain, &servAddr, sizeof(servAddr)); getsockname(sockMain, &servAddr, &length);
Вызов bind имеет форму:
возвращаемый_код = bind(дескриптор_socket, адресная_структура, длина_адресной_структуры)
Если адресная структура идентифицирует нужный порт, bind попытается получить его на сервере. Если переменная порта имеет значение 0, bind получит один из неиспользованных портов. Функция bind позволяет ввести номер порта и IP-адрес в TCB. Вызов getsockname имеет форму:
возвращаемый_код = getsockname(дескриптор_socket, адресная_структура, длина_адресной_структуры)
Мы запросили у bind выделение порта, но эта функция не сообщает нам, какой именно порт был предоставлен. Для выяснения этого нужно прочитать соответствующие данные из TCB. Функция getsockname() извлекает информацию из TCB и копирует ее в адресную структуру, где можно будет прочитать эти сведения. Номер порта извлекается и выводится следующим оператором:
printf("SERVER: Номер порта %d ", ntohs(servAddr.sin_port));
Функция ntohs() имеет полное название network-to-host-short и служит для преобразования номера порта из порядка следования байт в сети в локальный порядок следования байт на хосте.
4. listen(sockMain, 5);
Вызов listen применяется для ориентированных на соединение серверов и имеет форму:
возвращаемый_код = listen(дескриптор_socket, размер_очереди)
Вызов listen указывает, что это будет пассивный socket, и создает очередь требуемого размера для хранения поступающих запросов на соединения.
5. sockClient = accept(sockMain, 0, 0);
Вызов accept имеет форму:
новым_дескриптор_socket = accept(дескриптор_socket,
клиентская_адресная_структура, длина_клиентской_адресной_структуры)
По умолчанию вызов блокируется до соединения клиента с сервером. Если указана переменная клиентская_адресная_структура, после соединения клиента в эту структуру будут введены IP-адрес и порт клиента. В этом примере программы не проверяются IP-адрес и номер порта клиента, а просто два последних поля параметра заполняются нулями.
6. child = fork();
…
close(sockMain);
В языке С команда fork создает новый дочерний процесс, который наследует все дескрипторы ввода/вывода родительской программы, а также имеет доступ к sockMain и sockClient. Операционная система отслеживает количество процессов, имеющих доступ к socket.
Соединение закрывается, когда последний обращающийся к socket процесс вызывает close(). Когда дочерний процесс закрывает sockMain, родительский процесс все еще имеет доступ к socket.
7. close(sockClient);
Этот вызов выполняется из родительской части программы. Когда родительский процесс закрывает sockClient, дочерний процесс все еще имеет доступ к socket.
8. msgLength = recv(sockClient, buf, BUFLEN, 0));
…
close(sockClient);
Вызов recv имеет форму:
длина_сообщения = recv(дескриптор_socket, буфер, длина_буфера, флаги)
По умолчанию вызов recv блокированный. Функции fcntl() или iocntl() позволяют изменить статус socket на неблокированный режим.
После получения данных дочерним процессом и вывода сообщения на печать, доступ к sockClient закрывается. Это заставит соединение перейти в фазу закрытия.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Асинхронные вызовы процедур
Асинхронные вызовы процедур Основное возражение, которое можно предъявить к программе ThreeSage.c (программа 10.5) в ее нынешнем виде, касается прекращения выполнения передающего и принимающего потоков с помощью функции TerminateThread. В комментариях, включенных в код, вам
Глава 5 Системные вызовы
Глава 5 Системные вызовы Ядро операционной системы предоставляет набор интерфейсов, благодаря которым процессы, работающие в пространстве пользователя, могут взаимодействовать с системой. Эти интерфейсы предоставляют пользовательским программам доступ к аппаратному
Вызовы syscall
Вызовы syscall Системные вызовы (часто называемые syscall в ОС Linux) обычно реализуются в виде вызова функции. Для них могут быть определены один или более аргументов (inputs), которые могут приводить к тем или иным побочным эффектам[25], например к записи данных в файл или к
9.2. Системные вызовы
9.2. Системные вызовы В этой книге практически повсеместно упоминаются системные вызовы, которые являются фундаментальными для программного окружения. На первый взгляд, они выглядят как обычные вызовы функций С. И это не случайно; они представляют собой специальную
Отложенные вызовы
Отложенные вызовы Отложенный вызов определяет функцию, вызов которой будет произведен ядром системы через некоторое время. Например, в SVR4 любая подсистема ядра может зарегистрировать отложенный вызов следующим образом:int co_ID = timeout(void (*fn)(), caddr_t arg, long delta);где fn() определяет
21.4 Вызовы socket
21.4 Вызовы socket Вызовы socket подготавливают сетевое взаимодействие путем создания блоков управления пересылкой (Transmission Control Block — TCB). В некоторых изданиях процесс создания TCB называется созданием socket. Вызов socket возвращает небольшое целое число, называемое дескриптором и
21.7.1 Вызовы в клиентской программе TCP
21.7.1 Вызовы в клиентской программе TCP 1. sock = socket(AF_INET, SOCK_STREAM, 0);Клиент создает блок управления пересылкой ("socket") так же, как это делал сервер.2. Сервер должен инициализировать адресную структуру для использования в bind.Эта структура содержит локальный IP-адрес и номер порта
21.10.1 Вызовы в серверной программе UDP
21.10.1 Вызовы в серверной программе UDP 1. sockMain = socket(AF_NET, SOCK_DGRAM, 0);Семейство адресов — снова Интернет.2. bzero((char *)&servAddr, sizeof(servAddr));servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = htonl(INADDR_ANY);servAddr.sin_port = 0;Вызовы инициализации адресной структуры сервера те же, что и в программе для TCP.3. bind(sockMain,
5.5.2. Системные вызовы
5.5.2. Системные вызовы Сокеты являются более гибкими в управлении, чем рассмотренные выше механизмы межзадачного взаимодействия. При работе с сокетами используются следующие функции:? socket() — создает сокет;? close() — уничтожает сокет;? connect() — устанавливает соединение
Вызовы функций
Вызовы функций Синтаксис:<выражение> (<список-выражений>)Значением <выражения> должен быть адрес функции. В простейшем случае это идентификатор функции. <Список выражений> содержит выражения, разделенные запятыми. Значение каждого из этих выражений
Рекурсивные вызовы
Рекурсивные вызовы Любая функция в Си-программе может быть вызвана рекурсивно; в частности, она может вызвать сама себя. Компилятор не ограничивает число рекурсивных вызовов одной функции. При каждом вызове новые ячейки памяти выделяются для формальных параметров и
Вызовы функций
Вызовы функций После установки Firebird содержит минимальный набор внутренних функций SQL. Хотя новые функции появляются время от времени, тем не менее сохраняется одно из основных достоинств Firebird: малый объем памяти, занимаемый сервером.Функциональные возможности сервера
Вызовы функций
Вызовы функций Вызовы функций имеют такой же синтаксис, как и вызовы процедур. Они могут быть квалифицированные и неквалифицированные: в первом случае используется нотация с многоточием. При соответствующих объявлениях класса и функций, они, например, таковы:b.fb.g(x, y,
Отправка данных серверной программе
Отправка данных серверной программе Предположим, мы создали несколько полей ввода, собирающих данные от пользователя. Как теперь отправить эти данные серверной программе?Прежде всего, их нужно поместить в переменные. Причем это должны быть переменные уровня клипа, т. е.
Получение данных от серверной программы
Получение данных от серверной программы Самый простой способ передать серверной программе данные и сразу же получить от нее результат их обработки — использовать действие loadVariabies или одноименный метод объекта movieClip. Это действие (метод) отправляет данные серверной