3.2. Получение данных
Для получения данных от партнера по сетевому взаимодействию используется системный вызов recv, имеющий следующий вид
#include <sys/types.h>
#include <sys/socket.h>
int recv (s, buf, len, flags)
int s;
char *buf;
int len;
int flags;
Аргумент s задает дескриптор socket'а, через который принимаются данные.
Аргумент buf указывает на область памяти, предназначенную для размещения принимаемых данных.
Аргумент len задает длину (в байтах) этой области.
Аргумент flags модифицирует исполнение системного вызова recv. При нулевом значении этого аргумента вызов recv полностью аналогичен системному вызову read.
При успешном завершении recv возвращает количество принятых в область, указанную аргументом buf, байт данных. Если канал данных, определяемый дескриптором s, оказывается "пустым", то recv переводит программу в состояние ожидания до момента появления в нем данных.
4. Функции закрытия связи
Для закрытия связи с партнером по сетевому взаимодействию используются системные вызовы close и shutdown.
4.1. Системный вызов close
Для закрытия ранее созданного socket'а используется обычный системный вызов close, применяемый в ОС UNIX для закрытия ранее открытых файлов и имеющий следующий вид
int close (s)
int s;
Аргумент s задает дескриптор ранее созданного socket'а.
Однако в режиме с установлением логического соединения (обеспечивающем, как правило, надежную доставку данных) внутрисистемные механизмы обмена будут пытаться передать/принять данные, оставшиеся в канале передачи на момент закрытия socket'а. На это может потребоваться значительный интервал времени, неприемлемый для некоторых приложений. В такой ситуации необходимо использовать описываемый далее системный вызов shutdown.
4.2. Сброс буферизованных данных
Для "экстренного" закрытия связи с партнером (путем "сброса" еще не переданных данных) используется системный вызов shutdown, выполняемый перед close и имеющий следующий вид
int shutdown (s, how)
int s;
int how;
Аргумент s задает дескриптор ранее созданного socket'а.
Аргумент how задает действия, выполняемые при очистке системных буферов socket'а:
0 - сбросить и далее не принимать данные для чтения из socket'а;
1 - сбросить и далее не отправлять данные для посылки через socket;
2 - сбросить все данные, передаваемые через socket в любом направлении.
5. Пример использования socket-интерфейса
В данном разделе рассматривается использование socket-интерфейса в режиме взаимодействия с установлением логического соединения на очень простом примере взаимодействия двух программ (сервера и клиента), функционирующих на разных узлах сети TCP/IP.
Содержательная часть программ примитивна:
сервер, приняв запрос на соединение, передает клиенту вопрос "Who are you?";
клиент, получив вопрос, выводит его в стандартный вывод и направляет серверу ответ "I am your client" и завершает на этом свою работу;
сервер выводит в стандартный вывод ответ клиента, закрывает с ним связь и переходит в состояние ожидания следующего запроса к нему.
Примечание. Предлагаемые ниже тексты программ предназначены только для иллюстрации логики взаимодействия программ через сеть, поэтому в них отсутствуют такие атрибуты программ, предназначенных для практического применения, как обработка кодов возврата системных вызовов и функций, анализ кодов ошибок в глобальной переменной errno, реакция на асинхронные события и т.п.
5.1. Программа-сервер
Текст программы-сервера на языке программирования СИ выглядит следующим образом
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <netdb.h>
5 #include <memory.h>
6 #define SRV_PORT 1234
7 #define BUF_SIZE 64
8 #define TXT_QUEST "Who are you?n"
9 main () {
10 int s, s_new;
11 int from_len;
12 char buf[BUF_SIZE];
13 struct sockaddr_in sin, from_sin;
14 s = socket (AF_INET, SOCK_STREAM, 0);
15 memset ((char *)&sin, '', sizeof(sin));
16 sin.sin_family = AF_INET;
17 sin.sin_addr.s_addr = INADDR_ANY;
18 sin.sin_port = SRV_PORT;
19 bind (s, (struct sockaddr *)&sin, sizeof(sin));
20 listen (s, 3);
21 while (1) {
22 from_len = sizeof(from_sin);
23 s_new = accept (s, &from_sin, &from_len);
24 write (s_new, TXT_QUEST, sizeof(TXT_QUEST));
25 from_len = read (s_new, buf, BUF_SIZE);
26 write (1, buf, from_len);
27 shutdown (s_new, 0);
28 close (s_new);
29 };
30 }
Строки 1...5 описывают включаемые файлы, содержащие определения для всех необходимых структур данных и символических констант.
Строка 6 приписывает целочисленной константе 1234 символическое имя SRV_PORT. В дальнейшем эта константа будет использована в качестве номера порта сервера. Значение этой константы должно быть известно и программе-клиенту.
Строка 7 приписывает целочисленной константе 64 символическое имя BUF_SIZE. Эта константа будет определять размер буфера, используемого для размещения принимаемых от клиента данных.
Строка 8 приписывает последовательности символов, составляющих текст вопроса клиенту, символическое имя TXT_QUEST. Последним символом в последовательности является символ перехода на новую строку 'n'. Сделано это для упрощения вывода текста вопроса на стороне клиента.
В строке 14 создается (открывается) socket для организации режима взаимодействия с установлением логического соединения (SOCK_STREAM) в сети TCP/IP (AF_INET), при выборе протокола транспортного уровня используется протокол "по умолчанию" (0).
В строках 15...18 сначала обнуляется структура данных sin, а затем заполняются ее отдельные поля. Использование константы INADDR_ANY упрощает текст программы, избавляя от необходимости использовать функцию gethostbyname для получения адреса локального узла, на котором запускается сервер.
Строка 19 посредством системного вызова bind привязывает socket, задаваемый дескриптором s, к порту с номером SRV_PORT на локальном узле. Bind завершится успешно при условии, что в момент его выполнения на том же узле уже не функционирует программа, использующая этот номер порта.
Строка 20 посредством системного вызова listen организует очередь на три входящих к серверу запроса на соединение.
Строка 21 служит заголовком бесконечного цикла обслуживания запросов от клиентов.
На строке 23, содержащей системный вызов accept, выполнение программы приостанавливается на неопределенное время, если очередь запросов к серверу на установление связи оказывается пуста. При появлении такого запроса accept успешно завершается, возвращая в переменной s_new дескриптор socket'а для обмена информацией с клиентом.
В строке 24 сервер с помощью системного вызова write отправляет клиенту вопрос.
В строке 25 с помощью системного вызова read читается ответ клиента.
В строке 26 ответ направляется в стандартный вывод, имеющий дескриптор файла номер 1. Так как строка ответа содержит в себе символ перехода на новую строку, то текст ответа будет размещен на отдельной строке дисплея.
Строка 27 содержит системный вывод shutdown, обеспечивающий очистку системных буферов socket'а, содержащих данные для чтения ("лишние" данные могут там оказаться в результате неверной работы клиента).
В строке 28 закрывается (удаляется) socket, использованный для обмена данными с очередным клиентом.
Примечание. Данная программа (как и большинство реальных программ-серверов) самостоятельно своей работы не завершает, находясь в бесконечном цикле обработки запросов клиентов. Ее выполнение может быть прервано только извне путем посылки ей сигналов (прерываний) завершения. Правильно разработанная программа-сервер должна обрабатывать такие сигналы, корректно завершая работу (закрывая, в частности, посредством close socket с дескриптором s).
5.2. Программа-клиент
Текст программы-клиента на языке программирования СИ выглядит следующим образом
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <netdb.h>
5 #include <memory.h>
6 #define SRV_HOST "delta"
7 #define SRV_PORT 1234
8 #define CLNT_PORT 1235
9 #define BUF_SIZE 64
10 #define TXT_ANSW "I am your clientn"
11 main () {
12 int s;
13 int from_len;
14 char buf[BUF_SIZE];
15 struct hostent *hp;
16 struct sockaddr_in clnt_sin, srv_sin;
17 s = socket (AF_INET, SOCK_STREAM, 0);
18 memset ((char *)&clnt_sin, '',
sizeof(clnt_sin));
19 clnt_sin.sin_family = AF_INET;
20 clnt_sin.sin_addr.s_addr = INADDR_ANY;
21 clnt_sin.sin_port = CLNT_PORT;
22 bind (s, (struct sockaddr *)&clnt_sin,
sizeof(clnt_sin));
23 memset ((char *)&srv_sin, '',
sizeof(srv_sin));
24 hp = gethostbyname (SRV_HOST);
25 srv_sin.sin_family = AF_INET;
26 memcpy ((char
*)&srv_sin.sin_addr,hp->h_addr,hp->h_length);
27 srv_sin.sin_port = SRV_PORT;
28 connect (s, &srv_sin, sizeof(srv_sin));
29 from_len = recv (s, buf, BUF_SIZE, 0);
30 write (1, buf, from_len);
31 send (s, TXT_ANSW, sizeof(TXT_ANSW), 0);
32 close (s);
33 exit (0);
34 }
В строках 6 и 7 описываются константы SRV_HOST и SRV_PORT, определяющие имя удаленного узла, на котором функционирует программа-сервер, и номер порта, к которому привязан socket сервера.
Строка 8 приписывает целочисленной константе 1235 символическое имя CLNT_PORT. В дальнейшем эта константа будет использована в качестве номера порта клиента.
В строках 17...22 создается привязанный к порту на локальном узле socket.
В строке 24 посредством библиотечной функции gethostbyname транслируется символическое имя удаленного узла (в данном случае "delta"), на котором должен функционировать сервер, в адрес этого узла, размещенный в структуре типа hostent.
В строке 26 адрес удаленного узла копируется из структуры типа hostent в соответствующее поле структуры srv_sin, которая позже (в строке 28) используется в системном вызове connect для идентификации программы-сервера.
В строках 29...31 осуществляется обмен данными с сервером и вывод вопроса, поступившего от сервера, в стандартный вывод.
Строка 32 посредством системного вызова close закрывает (удаляет) sock
... хранимых процедур на других серверах. RPC представляет собой достаточно удобный способ работы с распределенными данными без необходимости внесения изменений в клиентскую часть приложения. MS Distributed Transaction Coordinator (DTC). Создание распределенных приложений приводит к тому, что транзакции также приобретают распределенный характер. Структуризация приложения в виде многих самостоятельных ...
... не зависимый от языка способ создания кода и привязки его к запросам Web-страниц, — .NET Web Forms — управляемую событиями программную модель взаимодействия с элементами управления. Она делает программирование Web-страниц аналогичным программированию форм Visual Basic. ASP.NET содержит развитые средства управления сеансами и функции защиты. Она надежнее, и производительность ее значительно выше ...
... октав, содержащая схему пpеобpазования воздействий в MIDI-сообщения и адаптеp с выходом MIDI Out. MIDI-клавиатура не способна звучать самостоятельно, она использует в качестве синтезатора звуковую карту компьютера. Иногда на MIDI-клавиатуре размещены некоторые дополнительные переключатели, например, глиссандо или вибрато. Большинство MIDI-клавиатур производится фирмой Fatar (под своей маркой их ...
... Заказчика ПО; 6. Правовые аспекты. 5.2 Технико-экономическое обоснование разработки ПО Данный программный продукт предназначен для помощи в работе лицам, ответственным за проведение маркетинговых исследований, начиная от создания анкеты и заканчивая обработкой полученных данных. Целью внедрения данного продукта является снижение издержек при проведении маркетинговых исследований– ...
0 комментариев