Vm78@onego.ruNET TECHNOLOGIES Программирование Socket'ов Socket (гнездо, разъем) - абстрактное программное понятие, используемое для обозначения в прикладной.

Презентация:



Advertisements
Похожие презентации
Корпоративные системы Лекция 3. Реализация архитектуры «Клиент- сервер» с использованием механизма сокетов.
Advertisements

СОКЕТЫ. СОКЕТ Сокет – программный интерфейс для обеспечения обмена данными между процессами. Впервые socket API появилась в BSD Unix. Описан в POSIX В.
Взаимодействие процессов: сокеты.
3. Механизм сокетов 3.1. Общие концепции 3.2. Интерфейсные функции для работы с сокетом Создание сокета Связывание и установление соединения.
Механизм сокетов Средства межпроцессного взаимодействия ОС Unix, представленные в системе IPС, решают проблему взаимодействия процессов, выполняющихся.
СЕТЕВОЕ ПРОГРАММИРОВАНИЕ В LINUX. Со́кеты Со́кеты (англ. socket углубление, гнездо, разъём) название программного интерфейса для обеспечения обмена данными.
ПАРАМЕТРЫ СОКЕТА Методическое пособие по дисциплине «Программное обеспечение компьютерных сетей и информационных систем»
Сокеты в Perl и PHP. Сокеты в Perl Сокеты являются «конечными пунктами» в процессе обмена данными. Одни типы сокетов обеспечивают надежный обмен данными,
Сокеты Сети и системы телекоммуникаций Созыкин А.В.
Сети ЭВМ и телекоммуникации. Состояния сеанса TCP CLOSED Начальное состояние узла LISTEN Сервер ожидает запросов установления соединения от клиента SYN-SENT.
Низкоуровневые операции в ИС. Сокеты в C#. Понятие сокета Если требуется получить доступ к сетевым операциям низкого уровня, в программе следует использовать.
СОКЕТЫ -2 РАБОТА СЕРВЕРА Стандартная схема работы плоха тем, что одновременно обслуживается только один клиент ! Это приводит к задержкам в работе сети.
Распределение памяти. Динамическое выделение памяти.
Интерфейс сокетов. Интерфейс прикладной программы (API) представляет собой просто набор функций (интерфейс), использующийся программистами для разработки.
Функции Функция – именованная последовательность описаний и операторов, выполняющая некоторое действие. Может иметь параметры и возвращать значение. Функция.
Учебный курс Объектно-ориентированный анализ и программирование Лекция 4 Трансформация логической модели в программный код Лекции читает кандидат технических.
Интернет Университет Суперкомпьютерных технологий Лекция 1 Основные понятия Учебный курс Введение в параллельные алгоритмы Якобовский М.В., д.ф.-м.н. Институт.
Работа с файлами Сазонов Д.О. ПМиЭММ Часть 2. Тема занятия: Работа с файлами через потоки Для реализации файлового ввода/вывода, необходимо включить в.
Лекция 6 Множественное распараллеливание на Linux кластере с помощью библиотеки MPI 1. Компиляция и запуск программы на кластере. 2. SIMD модель параллельного.
Введение в параллельные вычисления. Технология программирования MPI (день второй) Антонов Александр Сергеевич, к.ф.-м.н., н.с. лаборатории Параллельных.
Транксрипт:

TECHNOLOGIES Программирование Socket'ов Socket (гнездо, разъем) - абстрактное программное понятие, используемое для обозначения в прикладной программе конечной точки канала связи с коммуникационной средой, образованной вычислительной сетью. При использовании протоколов TCP/IP можно говорить, что socket является средством подключения прикладной программы к порту локального узла сети. Создание socket'а …………………………………… Связывание socket'а ………………………………… Ожидание установления связи ……………………. Запрос на установление соединения……………… Прием запроса на установление связи ……………. Завершение accept…………………………………… Формирование адреса узла сети …………………… Функции обмена данными ………………………… Отправка данных …………………………………… Получение данных …………………………………. Закрытие связи. Системный вызов close …………. Закрытие связи. Сброс буферизованных данных … Пример использования socket-интерфейса ……….. Слайд CОДЕРЖАНИЕ студент заочного отделения 4 курса ЗУ АСОИУ Михайлов Валентин Владимирович, февраль, 2006

TECHNOLOGIES Создание socket'а Аргумент domain задает используемый для взаимодействия набор протоколов (вид коммуникационной области), для стека протоколов TCP/IP он должен иметь символьное значение AF_INET (определено в sys/socket.h). Аргумент type задает режим взаимодействия: SOCK_STREAM - с установлением соединения; SOCK_DGRAM - без установления соединения. Аргумент protocol задает конкретный протокол транспортного уровня (из нескольких возможных в стеке протоколов). Если этот аргумент задан равным 0, то будет использован протокол "по умолчанию" (TCP для SOCK_STREAM и UDP для SOCK_DGRAM при использовании комплекта протоколов TCP/IP). При удачном завершении своей работы данная функция возвращает дескриптор socket'а - целое неотрицательное число, однозначно его идентифицирующее. Дескриптор socket'а аналогичен дескриптору файла ОС UNIX. При обнаружении ошибки в ходе своей работы функция возвращает число "-1". #include int socket (domain, type, protocol) int domain; int type; int protocol; Создание socket'а осуществляется следующим системным вызовом

TECHNOLOGIES Связывание socket'а # 1 Для подключения socket'а к коммуникационной среде, образованной вычислительной сетью, необходимо выполнить системный вызов bind, определяющий в принятом для сети формате локальный адрес канала связи со средой. В сетях TCP/IP socket связывается с локальным портом. Системный вызов bind имеет следующий синтаксис: #include int bind (s, addr, addrlen) int s; struct sockaddr *addr; int addrlen; Аргумент s задает дескриптор связываемого socket'а. Аргумент addr в общем случае должен указывать на структуру данных, содержащую локальный адрес, приписываемый socket'у. Для сетей TCP/IP такой структурой является sockaddr_in. Аргумент addrlen задает размер (в байтах) структуры данных, указываемой аргументом addr.

TECHNOLOGIES Связывание socket'а # 2 Структура sockaddr_in используется несколькими системными вызовами и функциями socket-интерфейса и определена в include- файле in.h следующим образом: struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; Поле sin_family определяет используемый формат адреса (набор протоколов), в нашем случае (для TCP/IP) оно должно иметь значение AF_INET. Поле sin_addr содержит адрес (номер) узла сети. Поле sin_port содержит номер порта на узле сети. Поле sin_zero не используется.

TECHNOLOGIES Связывание socket'а # 3 Определение структуры in_addr (из того же include-файла) таково: struct in_addr { union { u_long S_addr; /*другие (не интересующие нас) члены объединения */ } S_un; #define s_addr S_un.S_addr }; Структура sockaddr_in должна быть полностью заполнена перед выдачей системного вызова bind. При этом, если поле sin_addr.s_addr имеет значение INADDR_ANY, то системный вызов будет привязывать к socket'у номер (адрес) локального узла сети. В случае успеха bind возвращает 0, в противном случае - "-1".

TECHNOLOGIES Ожидание установления связи Системный вызов listen выражает желание выдавшей его программы-сервера ожидать запросы к ней от программ-клиентов и имеет следующий вид: #include int listen (s, n) int s; int n; Аргумент s задает дескриптор socket'а, через который программа будет ожидать запросы к ней от клиентов. Socket должен быть предварительно создан системным вызовом socket и обеспечен адресом с помощью системного вызова bind. Аргумент n определяет максимальную длину очереди входящих запросов на установление связи. Если какой-либо клиент выдаст запрос на установление связи при полной очереди, то этот запрос будет отвергнут. Признаком удачного завершения системного вызова listen служит нулевой код возврата.

TECHNOLOGIES Запрос на установление соединения Для обращения программы-клиента к серверу с запросом на установление логической соединения используется системный вызов connect: #include int connect (s, addr, addrlen) int s; struct sockaddr_in *addr; int addrlen; Аргумент s задает дескриптор socket'а, через который программа обращается к серверу с запросом на соединение. Socket должен быть предварительно создан системным вызовом socketи обеспечен адресом с помощью системного вызова bind. Аргумент addr должен указывать на структуру данных, содержащую адрес, приписанный socket'у программы-сервера, к которой делается запрос на соединение. Для сетей TCP/IP такой структурой является sockaddr_in. Для формирования значений полей структуры sockaddr_in удобно использовать функцию gethostbyname. Аргумент addrlen задает размер (в байтах) структуры данных, указываемой аргументом addr. Для того, чтобы запрос на соединение был успешным, необходимо, по крайней мере, чтобы программа-сервер выполнила к этому моменту системный вызов listen для socket'а с указанным адресом. При успешном выполнении запроса системный вызов connect возвращает 0, в противном случае - "-1" (устанавливая код причины неуспеха в глобальной переменной errno).

TECHNOLOGIES Прием запроса на установление связи Для приема запросов от программ-клиентов на установление связи в программах- серверах используется системный вызов accept, имеющий следующий вид: #include int accept (s, addr, p_addrlen) int s; struct sockaddr_in *addr; int *p_addrlen; Аргумент s задает дескриптор socket'а, через который программа-сервер получила запрос на соединение (посредством системного запроса listen ). Аргумент addr должен указывать на область памяти, размер которой позволял бы разместить в ней структуру данных, содержащую адрес socket'а программы-клиента, сделавшей запрос на соединение. Никакой инициализации этой области не требуется. Аргумент p_addrlen должен указывать на область памяти в виде целого числа, задающего размер (в байтах) области памяти, указываемой аргументом addr. Системный вызов accept извлекает из очереди, организованной системным вызовом listen, первый запрос на соединение и возвращает дескриптор нового (автоматически созданного) socket'а с теми же свойствами, что и socket, задаваемый аргументом s. Этот новый дескриптор необходимо использовать во всех последующих операциях обмена данными.

TECHNOLOGIES Прием запроса на установление связи Завершение accept После удачного завершения accept: а) область памяти, указываемая аргументом addr, будет содержать структуру данных (для сетей TCP/IP это sockaddr_in), описывающую адрес socket'а программы-клиента, через который она сделала свой запрос на соединение; б) целое число, на которое указывает аргумент p_addrlen, будет равно размеру этой структуры данных. Если очередь запросов на момент выполнения accept пуста, то программа переходит в состояние ожидания поступления запросов от клиентов на неопределенное время (хотя такое поведение accept можно и изменить). Признаком неудачного завершения accept служит отрицательное возвращенное значение (дескриптор socket'а отрицательным быть не может). Примечание. Системный вызов accept используется в программах- серверах, функционирующих только в режиме с установлением соединения.

TECHNOLOGIES Формирование адреса узла сети Для получения адреса узла сети TCP/IP по его символическому имени используется библиотечная функция #include struct hostent *gethostbyname (name) char *name; Аргумент name задает адрес последовательности литер, образующих символическое имя узла сети. При успешном завершении функция возвращает указатель на структуру hostent, определенную в include-файле netdb.h и имеющую следующий вид struct hostent { char *h_name; char **h_aliases; int h_addrtype; int h_lenght; char *h_addr; }; Поле h_name указывает на официальное (основное) имя узла. Поле h_aliases указывает на список дополнительных имен узла (синонимов), если они есть. Поле h_addrtype содержит идентификатор используемого набора протоколов, для сетей TCP/IP это поле будет иметь значение AF_INET. Поле h_lenght содержит длину адреса узла. Поле h_addr указывает на область памяти, содержащую адрес узла в том виде, в котором его используют системные вызовы и функции socket-интерфейса.

TECHNOLOGIES Функции обмена данными В режиме с установлением логического соединения после удачного выполнения пары взаимосвязанных системных вызовов connect (в клиенте) и accept (в сервере) становится возможным обмен данными. Этот обмен может быть реализован обычными системными вызовами read и write, используемыми для работы с файлами (при этом вместо дескрипторов файлов в них задаются дескрипторы socket'ов). Кроме того могут быть дополнительно использованы системные вызовы send и recv, ориентированные специально на работу с socket'ами. Примечание. Для обмена данными в режиме без установления логического соединения используются, как правило, системные вызовы sendto и recvfrom. Sendto позволяет специфицировать вместе с передаваемыми данными (составляющими дейтаграмму) адрес их получателя. Recvfrom одновременно с доставкой данных получателю информирует его и об адресе отправителя.

TECHNOLOGIES Отправка данных Для отправки данных партнеру по сетевому взаимодействию используется системный вызов send: #include int send (s, buf, len, flags) int s; char *buf; int len;int flags; Аргумент s задает дескриптор socket'а, через который посылаются данные. Аргумент buf указывает на область памяти, содержащую передаваемые данные. Аргумент len задает длину (в байтах) передаваемых данных. Аргумент flags модифицирует исполнение системного вызова send. При нулевом значении этого аргумента вызов send полностью аналогичен системному вызову write. При успешном завершении send возвращает количество переданных из области, указанной аргументом buf, байт данных. Если канал данных, определяемый дескриптором s, оказывается "переполненным", то send переводит программу в состояние ожидания до момента его освобождения.

TECHNOLOGIES Получение данных Для получения данных от партнера по сетевому взаимодействию используется системный вызов recv, имеющий следующий вид #include 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 переводит программу в состояние ожидания до момента появления в нем данных.

TECHNOLOGIES Закрытие связи Системный вызов close Для закрытия ранее созданного socket'а используется обычный системный вызов close, применяемый в ОС UNIX для закрытия ранее открытых файлов: int close (s) int s; Аргумент s задает дескриптор ранее созданного socket'а. Однако в режиме с установлением логического соединения (обеспечивающем, как правило, надежную доставку данных) внутрисистемные механизмы обмена будут пытаться передать/принять данные, оставшиеся в канале передачи на момент закрытия socket'а. На это может потребоваться значительный интервал времени, неприемлемый для некоторых приложений. В такой ситуации необходимо использовать системный вызов shutdown.

TECHNOLOGIES Закрытие связи Сброс буферизованных данных Для "экстренного" закрытия связи с партнером (путем "сброса" еще не переданных данных) используется системный вызов shutdown, выполняемый перед close: int shutdown (s, how) int s; int how; Аргумент s задает дескриптор ранее созданного socket'а. Аргумент how задает действия, выполняемые при очистке системных буферов socket'а: 0 - сбросить и далее не принимать данные для чтения из socket'а; 1 - сбросить и далее не отправлять данные для посылки через socket; 2 - сбросить все данные, передаваемые через socket в любом направлении.

TECHNOLOGIES Пример использования socket-интерфейса Взаимодействие с установлением логического соединения двух программ (сервера и клиента), функционирующих на разных узлах сети TCP/IP. Смысл работы: 1.Сервер, приняв запрос на соединение, передает клиенту вопрос «What is your login?» 2. Клиент, получив вопрос, выводит его в стандартный вывод и направляет серверу ответ vm78" и завершает на этом свою работу. 3.Сервер выводит в стандартный вывод ответ клиента, закрывает с ним связь и переходит в состояние ожидания следующего запроса к нему. Листинги программ с комментариями см. на слайдах

TECHNOLOGIES Пример. Программа-сервер # 1 1 #include 2 #include 3 #include 4 #include 5 #include 6 #define SRV_PORT #define BUF_SIZE 64 8 #define TXT_QUEST " What is your login?\n" 9 main () { 10int s, s_new; 11int from_len; 12char buf[BUF_SIZE]; 13struct sockaddr_in sin, from_sin; Строки описывают включаемые файлы, содержащие определения для всех необходимых структур данных и символических констант. Строка 6 приписывает целочисленной константе 1234 символическое имя SRV_PORT. В дальнейшем эта константа будет использована в качестве номера порта сервера. Значение этой константы должно быть известно и программе-клиенту. Строка 7 приписывает целочисленной константе 64 символическое имя BUF_SIZE. Эта константа будет определять размер буфера, используемого для размещения принимаемых от клиента данных. Строка 8 приписывает последовательности символов, составляющих текст вопроса клиенту, символическое имя TXT_QUEST. Последним символом в последовательности является символ перехода на новую строку '\n'. Сделано это для упрощения вывода текста вопроса на стороне клиента.

TECHNOLOGIES Пример. Программа-сервер # 2 14s = socket (AF_INET, SOCK_STREAM, 0); 15memset ((char *)&sin, '\0', sizeof(sin)); 16sin.sin_family = AF_INET; 17sin.sin_addr.s_addr = INADDR_ANY; 18sin.sin_port = SRV_PORT; 19bind (s, (struct sockaddr *)&sin, sizeof(sin)); 20listen (s, 3); В строке 14 создается (открывается) socket для организации режима взаимодействия с установлением логического соединения (SOCK_STREAM) в сети TCP/IP (AF_INET), при выборе протокола транспортного уровня используется протокол "по умолчанию" (0). В строках сначала обнуляется структура данных sin, а затем заполняются ее отдельные поля. Использование константы INADDR_ANY упрощает текст программы, избавляя от необходимости использовать функцию gethostbyname для получения адреса локального узла, на котором запускается сервер. Строка 19 посредством системного вызова bind привязывает socket, задаваемый дескриптором s, к порту с номером SRV_PORT на локальном узле. Bind завершится успешно при условии, что в момент его выполнения на том же узле уже не функционирует программа, использующая этот номер порта. Строка 20 посредством системного вызова listen организует очередь на три входящих к серверу запроса на соединение.

TECHNOLOGIES Пример. Программа-сервер # 3 21while (1) { 22from_len = sizeof(from_sin); 23s_new = accept (s, &from_sin, &from_len); 24write (s_new, TXT_QUEST, sizeof(TXT_QUEST)); 25from_len = read (s_new, buf, BUF_SIZE); 26write (1, buf, from_len); 27shutdown (s_new, 0); 28close (s_new); 29 }; 30 } Строка 21 служит заголовком бесконечного цикла обслуживания запросов от клиентов. На строке 23, содержащей системный вызов accept, выполнение программы приостанавливается на неопределенное время, если очередь запросов к серверу на установление связи оказывается пуста. При появлении такого запроса accept успешно завершается, возвращая в переменной s_new дескриптор socket'а для обмена информацией с клиентом. В строке 24 сервер с помощью системного вызова write отправляет клиенту вопрос. В строке 25 с помощью системного вызова read читается ответ клиента. В строке 26 ответ направляется в стандартный вывод, имеющий дескриптор файла номер 1. Так как строка ответа содержит в себе символ перехода на новую строку, то текст ответа будет размещен на отдельной строке дисплея. Строка 27 содержит системный вывод shutdown, обеспечивающий очистку системных буферов socket'а, содержащих данные для чтения ("лишние" данные могут там оказаться в результате неверной работы клиента). В строке 28 закрывается (удаляется) socket, использованный для обмена данными с очередным клиентом.

TECHNOLOGIES Пример vm78. Программа-клиент 1 #include 2 #include 3 #include 4 #include 5 #include 6 #define SRV_HOST "delta" 7 #define SRV_PORT #define CLNT_PORT #define BUF_SIZE #define TXT_ANSW vm78\n" 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, '\0', 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, '\0', 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. В дальнейшем эта константа будет использована в качестве номера порта клиента. В строках создается привязанный к порту на локальном узле socket. В строке 24 посредством библиотечной функции gethostbyname транслируется символическое имя удаленного узла (в данном случае "delta"), на котором должен функционировать сервер, в адрес этого узла, размещенный в структуре типа hostent. В строке 26 адрес удаленного узла копируется из структуры типа hostent в соответствующее поле структуры srv_sin, которая позже (в строке 28) используется в системном вызове connect для идентификации программы-сервера. В строках осуществляется обмен данными с сервером и вывод вопроса, поступившего от сервера, в стандартный вывод. Строка 32 посредством системного вызова close закрывает (удаляет) socket.