Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СистПриклПрогЗабез(Хихловская).doc
Скачиваний:
25
Добавлен:
10.02.2016
Размер:
961.02 Кб
Скачать

Пример использования сокетов

Сокеты принадлежат домену UNIX, клиент посылает серверу сообщение “Hello”, а сервер отправляет его обратно клиенту, который после получения выводит сообщение на экран. Т.к. обмен данными происходит внутри одной ОСUNIX, сокеты датаграмм, которые здесь используются, не отличаются от сокетов потока. В качестве адреса сервера предлагается имя файла ./echo.server, считается что он один из данного каталога запущен. Предполагается, что клиенты знают этот адрес. Сервер связывает созданный сокет с этим локальным адресом и таким образом регистрируется в системе, после чего он готов к получению и обработке сообщений. Сервер начинает бесконечный цикл, ожидая сообщений от клиентов и блокируясь на вызовеrecvfrom(2). При получении сообщений сервер отправляет его обратно, вызываяsendto(2)

Сервер:

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#define MAXBUF 256

char buf [MAXBUF];

main()

{ struct sockaddr_un serv_addr, clnt_addr;

int sockfd;

int saddrlen, caddrlen, max_caddrlen, n;

/*создадим сокет*/

if ((sockfd = coscket(AF)UNIX, SOCK_DGRAM, 0))<0 {

printf(«невозможно создать сокет/n»);exit(1);

/* свяжем сокет с известным локальным адресом. Т.к. адрес в домене UNIXпредставляет собой имя файла, который будет создан системным вызовомbind(2), сначала следует удалить файл с этим именем в случае, если он сохранился от предыдущего запуска сервера */

unlink (“,/echo.server”);

bzero (s serv_addr, sizeof (serv_addr));

serv_addr.sun_family = AF_UNIX;

strcpy (serv _addr. Sun_path, “./echo.server”);

saddrlen = sizeof (serv_addr. Sun_family) + strlen(serv_addr. Sun_path);

if (bind (sockfd, (struct sockaddr *) f serv_addr, saddrlen)<0)

{printf(«ошибка связывания сокета с адресом./n»);

exit(1);

}

/*запускается бесконечный цикл чтения сообщений от клиентов и отправления их обратно*/

max_caddrlen=sizeof(clnt_addr);

for( ; ;) {

caddrlen=max_caddrlen;

n=recvfrom(socket, buf, MAXBUF, 0, (struct sockaddr*) & clnt_addr, & caddrlen);

if (n<0) {“ошибка приема./n”); exit(1);}

/* благодаря вызову recvfrom(2), становится известным адрес клиента, от которого получено сообщений. Этот адрес используется для передачи сообщения одратно отправителю*/

if(sendto(sockfd,buf,n,0 (structsockaddr*) &clnt_addr,caddrlen) :=n){

print(”ошибка передичи/n”);exit(1);}

}

}

Клиент создает сокет датаграмм и связывает его со своим уникальным адресом, который определяется уникальностью имени файла (одновременно могут работать несколько клиентов). Для обеспечения уникальности используется mktemp(3e), позволяющая по заданному шаблону /tmp/clnt.XXXXи на основании идентификатора текущего процесса получить уникальное имя, заменяя символы «ХХХХ». Связывание сокета позволяет при отправлении сообщения неявно указать его «адрес отправления», так что сервер отправляет его обратно.

Клиент

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#include NULL 0

char *msg=”Hello/n”;

#define MAXBUF 256

char buf [MAXBUF];

main ()

{

struct sockaddr_un serv_addr, clnt_addr;

int sockfd;

int saddrlen, caddrlen, msglen, n;

/*Установим адрес сервера, с которым мы будем обмениваться данными. Для этого заполняется структура данных sockaddr_un, которая используется при отправлении данных серверу с помощью вызоваsendto(). Значение адреса известно по предварительной договоренности */.

Bzero(fserv)addr,sizeof(serv_addr));

Serv_adr.sun_family=AF_UNIX;

Strcpy(serv_addr.sun_paht, “./echo.server”);

Saddrlen=sizeof(serv_addr.sun_family)+strlen(sorv_addr.sun_path);

/*создадим сокет датаграмм*/

if ((socket=socket(AF_UNIX,sock_dgram,0))<0) {

printf(“невозиожно создать сокет.n”);exit(1);}

/*Необходимо связать socketс некоторыми локальным адресом, чтобы сервер мог возвратить посланное сообщение. Этот адрес должен быть уникальным в пределах коммуникационного домена – данной ОС. Для обеспечения этого условия используется функцияmkstemp(3c), которая возвращает уникальное имя, основанное на представленном шаблоне и идентификаторе процессаPID*/

bzero (& clnt_addr, sizeof(clnt_addr));

clnt_addr.sun_family = AF_UNIX;

strepy(cl_addr.sun_path,”/tmp/clnt.XXXX”);

mkstmp(clnt_addr.sun_path);

caddrlen=sizeof(clnt_addr.sun_family)+atrlen(clnt_addr.sun_path);

if (bind sochfd, (struct sockaddr*)& clnt_addr,c addrlen)<0)

{

printf(‘ошибка связывания 0сокета.n’);exit(1);

}

/*отправление текста “Hello”

msglen=strlen(msg);

if (sendto(sockfd, msg, msglen,0,(struct sockaddr *)&serv_addr, saddrlen)!=msglen)

print(“ошибка передачи сообщения /n”);exit(1);

}

/*Чтение эха*/

if((n=recvfrom(sockfd,buf,MAXBUF,0,NULL,0))<0)

printf(“Ошибка получения сообщения/n”);

exit(1);

/*и вывод его на экран */

ptint (“эхо%; s/n”,buf);

/*Уничтожение сокета*/

close (sockfd);

unlink (clnt_addr.sun_path);

exit(0);

}

Сравнение различных систем межпроцесорного взаимодействия

Каналы

FIFO

Сообщения

Разделяемая память

Сокеты домен UNIX

Пространство имен

__________

Ключ

Ключ

Имя файла

Объект

Системный канал

Именование канала

Очередь сообщений

Разделяемая память

Коммуникационный узел

Создание объекта

Pipe()

Mknod()

Msgget()

Shmdet()

Socket()

Связывание

Pipe()

Open

Msgget()

Shmat()

Bind()

Connect()

Передача данных

Read()

Write()

Read()

Write()

Msgrcv()

Msgshd()

Непосредственный доступ

Read()

Write()

Recv()

Send()

Recvfrom()

Sendtu()

Уничтожение

Close(0)

Close(0)

Unlink()

Msgcte()

Shmdt()

Close()

unlink

Наиболее быстрый способ передачи данных является разделяемая память. Она является частью адресного пространства для каждого из взаимодействующих процессов, поэтому запись и чтение в эту память неотличимы от записи и чтения в области собственных данных процесса. Здесь возникает проблема синхронизации процессов. При использовании семафоров могут увеличиваться очереди на выполнение, т.к. несколько процессов могут быть одновременно разбужены и переведены в очередь на систему, но семафоры стандартизованы в POSIX. Очереди размером до 1 кБ служат для обмена короткими структурами данных. При их увеличении повышается число системных вызовов, что уменьшает производительность системы.

Интенсивность межпроцессного взаимодействия в системе можно определить с помощью команды sar-m. Вывод команды показывает число использования объектовJPEв секунду:

Msg/ssema/s

0.20 20.00

0.60 12.20

2.20 10.40