Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Лабораторная работа № 25



Клиент-серверные взаимодействия посредством сокетов в режиме TCP-соединения

Цель работы: практическое освоение механизма сокетов. Построение TCP-соединений для межпроцессного взаимодействия программ клиента и сервера в модели "клиент-сервер".

Существует две модели взаимодействия между процессами в сети: модель соединений с протоколом TCP (Transmission Control Protocol), и модель дейтаграмм с протоколом UDP (User Datagram Protocol). В данной лабораторной работе используется первая из названных моделей.

Далее приводятся основные шаги и необходимые системные вызовы для выполнения основных этапов при работе с сокетами в режиме TCP-соединения.

1. Адресация и создание сокета

Совокупная информация об адресе, порте программы-адресата (абонента), модели соединения, протоколе взаимодействия составляет так называемый сокет (конечная абонентская точка), формально представляющий собой структуру данных. Существует несколько видов сокетов:

· обобщенный сокет (generic socket), определяется в файле <sys/socket.h>:

struct sockaddr

{

u_char sa_family; /* Семейство адресов (домен) */

char sa_data[]; /* Адрес сокета */

};

· сокеты для связи через сеть, определяются в файле <netinet/in.h>

struct sockaddr_in

{

u_char sin_len; /* Длина поля sockaddr_in (для FreeBSD) */

u_char sin_family; /* Семейство адресов (домен) */

u_short sin_port; /* Номер порта */

struct in_addr sin_addr; /* IP-адрес */

char sin_zero[8]; /* Поле выравнивания */

};

где

struct in_addr

{

n_int32_t s_addr

};

Создается сокет при помощи системного вызова socket()

#include <sys/socket.h>

int socket (int domain, int type, int protocol);

· параметр domain - домен связи, в котором будет использоваться сокет (значение AF_INET - для домена Internet (соединение через сеть), AF_UNIX - домен, если процессы находятся на одном и том же компьютере);

· параметр type определяет тип создаваемого сокета (значение SOCK_STREAM - для режима соединений, SOCK_DGRAM - для режима дейтаграмм);

· Параметр protocol определяет используемый протокол (в случае protocol=0 по умолчанию для сокета типа SOCK_STREAM будет использовать протокол TCP, а для сокета типа SOCK_DGRAM - протокол UDP).

При программировании TCP-соединения должны быть созданы сокеты (системный вызов socket()) и в программе сервера, и в программе клиента, при этом в обеих программах сокеты связываются с адресом машины, на которую будет установлена программа сервера. Но, если в программе сервера для определения IP-адреса в структуре сокета может быть использована переменная INADDR_ANY, то в программе клиента для занесения в структуру сокета IP-адреса машины сервера необходимо использовать системный вызов inet_addr().

Сетевые вызовы inet_addr() и inet_ntoa() выполняют преобразования IP-адреса из формата текстовой строки "x.y.z.t" в структуру типа in_addr и обратно.

#include <arpa/inet.h>

in_addr_t inet_addr (const char *ip_address);

char * inet_ntoa(const struct in_addr in);

Для того чтобы процесс мог ссылаться на адрес своего компьютера, в файле <netinet/in.h> определена переменная INADDR_ANY, содержащая локальный адрес компьютера в формате in_addr_t.

2. Связывание

Системный вызов bind() связывает сетевой адрес компьютера с идентификатором сокета.

#include <sys/types.h>

#include <sys/socket.h>

int bind (int sockfd, const struct sockaddr *address, size_t add_len);

· sockfd - дескриптор файла сокета, созданным с помощью вызова socket();

· address - указатель на обобщённую структуру адреса сокета, к которой преобразуется структура sockaddr_in в случае передачи данных через сеть;

· size_t add_len - размер указанной структуры адреса сокета.

В случае успешного завершения вызова bind() он возвращает значение 0. В случае ошибки, например, если сокет для этого адреса уже существует, вызов bind() возвращает значение -1. Переменная errno будет иметь при этом значение EADDRINUSE.

Операция связывания выполняется только в программе сервера.

3. Включение приема TCP-соединений

После выполнения связывания с адресом и перед тем, как какой-либо клиент сможет подключиться к созданному сокету, сервер должен включить прием соединений посредством системного вызова listen():

#include <sys/socket.h>

int listen (int sockfd, int queue_size);

· sockfd - дескриптор файла сокета, созданный с помощью вызова socket();

· queue_size - число запросов на соединение с сервером, которые могут стоять в очереди.

Данная операция выполняется только в программе сервера.

4. Прием запроса на установку TCP-соединения

Когда сервер получает от клиента запрос на соединение, он создаёт новый сокет для работы с новым соединением. Первый же сокет используется только для установки соединения. Дополнительный сокет для работы с соединением создаётся при помощи вызова accept(), принимающего очередное соединение:

#include <sys/types.h>

#include <sys/socket.h>

int accept (int sockfd, struct sockaddr *address, size_t *add_len);

· sockfd - дескриптор сокета, для которого ведется прием соединений;

· address - указатель на обобщенную структуру адреса сокета с информацией о клиенте; так как связь использует соединение адрес клиента знать не обязательно и допустимо задавать параметр address значением NULL;

· add_len - размер структуры адреса, заданной параметром address, если значение address не равно NULL.

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

Данная операция выполняется только в программе сервера.

5. Подключение клиента

Для выполнения запроса на подключение к серверному процессу клиент использует системный вызов connect():

#include <sys/types.h>

#include <sys/socket.h>

int connect (int csockfd, const struct sockaddr *address, size_t add_len);

· сsockfd - дескриптор файла сокета клиента, созданным с помощью вызова socket();

· address - указателем на обобщенную структуру адреса сокета, к которой преобразуется структура sockaddr_in, в случае передачи данных через сеть;

· size_t add_len - размер указанной структуры адреса сокета.

В случае успешного завершения вызова connect() он возвращает значение 0. В случае ошибки, системный вызов connect() возвращает значение -1, а переменная errno идентифицирует ошибку.

Данная операция выполняется только в программе клиента.

6. Пересылка данных

Для сокетов типа SOCK_STREAM дескрипторы сокетов, полученные сервером посредством вызова accept() и клиентом с помощью вызова socked(), могут использоваться для чтения или записи. Для этого могут использоваться обычные вызовы read() и write(), либо специальные системные вызовы send() и recv(), позволяющие задавать дополнительные параметры пересылки данных по сети. Синхронизация данных при работе с сокетом аналогична передаче данных через программный канал.

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recv (int sockfd, void *buffer, size_t length, int flags);

ssize_t send (int sockfd, const void *buffer, size_t length, int flags);

· socfd - дескриптор сокета, через который читаются или записываются данные;

· buffer - буфер, в который они помещаются или откуда отсылаются через сокет;

· length - размер буфера;

· flags - поле дополнительных опций при получении или передаче данных.

В случае успешного чтения/записи системные вызовы send() и recv() возвращают число прочитанных/отосланных байт, или -1 в случае ошибки; в случае разорванной связи (клиент разорвал TCP-соединение) вызов recv() (или read()) возвращают нулевое значение; если процесс пытается записать данные через разорванное TCP-соединение посредством write() или send(), то он получает сигнал SIGPIPE, который можно обработать, если предусмотрена обработка данного сигнала.

В случае flags=0 вызовы send() и recv() полностью аналогичны системным вызовам read() и write().

Возможные комбинациями констант параметра flags системного вызова send():

· MSG_PEEK - процесс может просматривать данные, не "получая" их;

· MSG_OOB - обычные данные пропускаются; процесс принимает только срочные данные, например, сигнал прерывания;

· MSG_WAITALL - возврат из вызова recv() произойдет только после получения всех данных.

Возможные комбинациями констант параметра flags системного вызова recv():

· MSG_OOB - передать срочные (out of band) данные;

· MSG_DONTROUTE - при передаче сообщения игнорируются условия маршрутизации протокола более низкого уровня. Обычно это означает, что сообщение посылается по прямому, а не по самому быстрому маршруту (самый быстрый маршрут не обязательно прямой и может зависеть от текущего распределения нагрузки сети).

Данные операции выполняются и в программе сервера и в программе клиента.

7. Закрытие TCP-соединения

Закрываются сокеты так же, как и обычные дескрипторы файлового ввода/вывода, - при помощи системного вызова close(). Для сокета SOCK_STREAM ядро гарантирует, что все записанные в сокет данные будут переданы принимающему процессу.

Данные операции выполняются и в программе сервера, и в программе клиента.





Дата публикования: 2015-10-09; Прочитано: 374 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.01 с)...