Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab5.rtf
Скачиваний:
1
Добавлен:
24.11.2019
Размер:
7.04 Mб
Скачать

2.3 Приклад використання сокета

Взаємодію поміж процесами за допомогою сокетів можна продемо-нструвати на прикладі домена UNIX. Функціональність розподіленої сис-теми у цьому разі полягає в тому, що клієнт надсилає серверові повідом-лення, сервер переспрямовує його клієнтові, який і виводить його післяотримання на термінал, оскільки у домені UNIXсокети дейтаграм практи-чно не відрізняються від сокетів потоку. Як адресу сервера можна зазначи-ти ім’я файла ./echo.server й припустити, що клієнти знають цю адресу.Сервер зв’язує створений сокет з цією локальною адресою і в такий спосібреєструється в системі. З цього моменту він готовий до приймання таопрацьовування повідомлень. Сервер починає нескінченний цикл, очікую-чи на повідомлення від клієнтів та блокуючись на виклику recvfrom(2).При отриманні повідомлення сервер надсилає його клієнтові, за допомо-гою виклику sendto(2). У додатку наведено програми серверної та клієнт-ської сторін. Клієнт створює сокет дейтаграм та зв’язує його зі своєю уні-кальною адресою, що зумовлюється унікальністю імені файла. Оскількиводночас можуть працювати кілька клієнтів, виникає проблема отриманняунікального імені. Для її розв’язання використовується функціяmktemp(3c), яка дозволяє за заданим шаблоном /tmp/clnt.XXXX та на під-ставі ідентифікатора поточного процесу отримати унікальне ім’я на замінусимволів ХХХХ. Зв’язування сокета дозволяє при відправлянні неявно за-значати його “адресу відправника”, тому сервер може повернути повідом-лення. У додатку Б (Лістинг1 та Лістинг 2) наведено вихідні тексти про-грам, що вони зреалізовують взаємодію поміж процесами, яка грунтуєтьсяна сокетах дейтаграм у домені UNIX.

3 Контрольні запитання

1

Які комунікаційні характеристики забезпечують сокети?

2

Які основні типи сокетів зреалізовано в BSD UNIX?

Створення програмного забезпечення телекомунікацій для роботи в ОСUNIX23

3Який системний виклик створює сокет та який він має опис?

4Що таке комунікаційні домени та які домени Ви знаєте?

5Який зв’язок існує поміж комунікаційними доменами та підтри-муваними ними сокетами?

6Якими параметрами схарактеризовується кожний комунікаційнийканал?

7Які системні виклики використовуються на серверному та клієнт-ському боці при створенні віртуального каналу з попереднім встановлен-ням з’єднання?

8Які системні виклики використовуються на серверному та клієнт-ському боці за взаємодії, яка грунтується на дейтаграмах?

9Яку довжину і формати мають адреси сокетів у різнихдоменах?

10 Яку адресу слід обирати для сервера й чому?

4 Домашнє завдання

1Коротко відповісти на контрольні запитання у письмовому вигля-ді.

2Переписати тексти клієнтської та серверної частин програми, яказорганізовує взаємодію процесів за протоколом UDP, та коментарі до них;тексти програм наведено у додатку Б (Лістинг1 та Лістинг2).

Список рекомендованої літератури

1Робачевский А. М. Операционная система UNIX.– СПб.: БХВ-Петербург, 2002.

2Ивановский С. Операционная система UNIX.– М.: Познаватель-ная книга плюс, 2000.

3Дегтярев Е. К. Введение в UNIX.– М.: МП "Память", 1991.

4http://www.freebsd.org.ru

5http://www.anriintern.com/computer/freebsd/

6http://www.linuxrsp.ru/freebsd/

Додаток А

Тексти програм serverfifo та clientfifo

Лістинг 1

serverfifo:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#define FIFO "/fifo.1"

#define MAXBUF 80

main()

{

int readfd, n;

char buff[MAXBUF];

if(mkfifo(FIFO, 0777) < 0){

printf("Nemozhlyvo stvoryty FIFO\n");

exit(1);

}

if((readfd = open(FIFO, O_RDONLY)) < 0){

printf("Nemozhlyvo vidkryty FIFO\n");

exit(1);

}

while((n = read(readfd, buff, MAXBUF)) > 0)

if(write(1, buff, n) != n){

printf("Pomylka vyvodu\n");

exit(1);

}

close(readfd);

exit(0);

}

Лістинг 2

clientfifo:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#define FIFO "/fifo.1"

main()

{

int writefd,n;

if((writefd = open(FIFO, O_WRONLY))<0) {

printf("Nemozhlyvo vidkryty FIFO\n");

exit(1);

}

if(write(writefd,"Dobryj denj, Svite!\n",21)!=21){

printf("Pomylka zapysu\n");

exit(1);

}

close(writefd);

if(unlink(FIFO) <0){

printf("Nemozhlyvo vyluchyty FIFO\n");

exit(1);

}

exit(0);

}

ДОДАТОК Б

Тексти програм socketserver та socketclient

Лістинг 1

socketserver:

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#define MAXBUF 256

#define FILE "echo.serv"

char buf[MAXBUF];

main()

{

struct sockaddr_un serv_addr, clnt_addr;

int sockfd;

int saddrlen, caddrlen, max_caddrlen, n;

if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){

printf("Nemozhlyvo stvoryty socket\n");

exit(1);

}

unlink(FILE);

bzero(&serv_addr, sizeof(serv_addr));

serv_addr.sun_family = AF_UNIX;

strcpy(serv_addr.sun_path, FILE);

saddrlen=sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path); if(bind(sockfd, (struct sockaddr*)&serv_addr, saddrlen) < 0){ printf("Pomylka svyazuvannya socketa z adresoyu\n");

exit(1);

}

max_caddrlen = sizeof(clnt_addr);

for(;;){

caddrlen = max_caddrlen;

n = recvfrom(sockfd, buf, MAXBUF, 0, (struct

sockaddr*)&clnt_addr, &caddrlen);

if(n < 0){

printf("Pomylka pryjmannya\n");

exit(1);

}

if(sendto(sockfd, buf, n, 0, (struct sockaddr*)&clnt_addr,caddrlen) !=n){

printf("Pomylka peredavannya\n");

exit(1);

}

}

}

Лістинг 2

socketclient:

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#include <errno.h>

#define MAXBUF 256

#define FILE "echo.serv"

#define NULL 0

char *msg = "Hello World!";

char buf[MAXBUF];

main()

{

struct sockaddr_un serv_addr, clnt_addr;

int sockfd;

int saddrlen, caddrlen, msglen, n;

bzero(&serv_addr, sizeof(serv_addr));

serv_addr.sun_family = AF_UNIX;

strcpy(serv_addr.sun_path, FILE);

saddrlen=sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path); if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){

printf("Nemozhlyvo stvoryty' socket\n");

exit(1);

}

bzero(&clnt_addr, sizeof(clnt_addr));

clnt_addr.sun_family = AF_UNIX;

strcpy(clnt_addr.sun_path, FILE);

mkstemp(clnt_addr.sun_path);

caddrlen=sizeof(clnt_addr.sun_family)+strlen(clnt_addr.sun_path); if(bind(sockfd, (struct sockaddr*)&clnt_addr, caddrlen) < 0){ printf("Pomylka svyazuvannya socketa\n");

exit(1);

}

msglen = strlen(msg);

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

printf("Pomylka peredavannya povidomlennya\n");

exit(1);

}

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

printf("Pomylka otrymannya povidomlennya\n");

exit(1);

}

printf("Echo: %s\n", buf);

close(sockfd);

unlink(clnt_addr.sun_path);

exit(0);

}

ДОДАТОК В

Тексти програм servertcp та clienttcp

Лістинг 1

servertcp:

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdio.h>

#include <fcntl.h>

#include <netdb.h>

#include <errno.h>

/*Номер порту сервера, відомий клієнтам*/

#define PORTNUM 1500

int main(int argc, char* argv[])

{

int s, ns, pid, nport;

struct sockaddr_in serv_addr, clnt_addr;

struct hostent *hp;

char buf[80], hname[80];

/*Перетворімо порядок слідування байтів на мережний формат*/ nport = PORTNUM;

nport = htons((u_short)nport);

/*Створімо сокет, який використовує протокол ТСР*/

if((s = socket(AF_INET, SOCK_STREAM, 0)) ==-1){

perror("Pomylka vyklyku socket()");

exit(1);

}

/*Задамо адресу комунікаційного вузла*/

bzero(&serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_addr.s_addr = INADDR_ANY;

serv_addr.sin_port = nport;

/*Зв'яжемо сокет з цією адресою*/

if(bind(s, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) ==-1){

perror("Pomylka vyklyku bind()");

exit(1);

}

/*Передамо повідомлення із зазначенням адреси сервера*/ fprintf(stderr, "Server gotov/j: %s\n",

inet_ntoa(serv_addr.sin_addr));

/*Сервер готовий приймати запити на встановлення з'єднання. Ма-ксимальна кількість запитів, які очікують на опрацювання- 5. Якправило,цієїкількості вистачає, щоби встигнути виконати ас-серt(2) та породитидочірній процес*/

if(listen(s, 5) ==-1){

perror("Pomylka vyklyku listen()");

exit(1);

}

/*Нескінченний цикл отримування запитів та їхнього опрацьову-вання*/

while(1){

int addrlen;

bzero(&clnt_addr, sizeof(clnt_addr));

addrlen = sizeof(clnt_addr);

/*Приймемо запит. Новий сокет ns стає комунікаційним вуз-лом створеного віртуального каналу*/

if((ns = accept(s, (struct sockaddr*) &clnt_addr, &addrlen))==

-1){

perror("Pomylka vyklyku accept()");

exit(1);

}

/*Виведемо інформацію про клієнта*/

fprintf(stderr, "Client = %s\n",

inet_ntoa(clnt_addr.sin_addr));

if((pid = fork()) ==-1){

perror("Pomylka vyklyku fork()");

exit(1);

}

if(pid == 0){

int nbytes, fout;

/*Дочірній процес: цей сокет нам не потрібен. Він

використовується, як і раніше, для отримання запитів*/

close(s);

/*Отримаємо повідомлення від клієнта й повернемо йо-го назад*/

while((nbytes = recv(ns, buf, sizeof(buf), 0)) != 0){ send(ns, buf, sizeof(buf), 0);

}

close(ns);

exit(0);

}

/*Батьківський процес: цей сокет нам не потрібен. Він ви-користовується дочірнім процесом для обміну даними*/

close(ns);

}

}

Лістинг 2

clienttcp:

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdio.h>

#include <fcntl.h>

#include <netdb.h>

#include <errno.h>

/*Номер порту, який обслуговується сервером*/

#define PORTNUM 1500

int

main(int argc, char* argv[])

{

int s, pid, i, j;

struct sockaddr_in serv_addr;

struct hostent *hp;

char buf[80] = "Hello, World!\n";

/*Клієнтові як аргумент передається доменне ім'я хоста, на яко-му запущено сервер. Доменне ім'я транслюється у адресу*/

if((hp = gethostbyname(argv[1])) == 0)

{

perror("Pomylka vyklyku gethostbyname()");

exit(3);

}

bzero(&serv_addr, sizeof(serv_addr));

bcopy(hp->h_addr, &serv_addr.sin_addr, hp->h_length);

serv_addr.sin_family = hp->h_addrtype;

serv_addr.sin_port = htons(PORTNUM);

/*Створімо сокет*/.

if((s = socket(AF_INET, SOCK_STREAM, 0)) ==-1){

perror("Pomylka vyklyku socket()");

exit(1);

}

fprintf(stderr, "Addresa clienta: %s\n",

inet_ntoa(serv_addr.sin_addr));

/*Створімо віртуальний канал*/

if(connect(s, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==

-1){

perror("Pomylka vyklyku connect()");

exit(1);

}

/*Передамо серверові повідомлення й отримаємо його назад*/ send(s, buf, sizeof(buf), 0);

if(recv(s, buf, sizeof(buf), 0) < 0){

perror("Pomylka vyklyku recv()");

exit(1);

}

/*Виведемо отримане повідомлення на екран*/

printf("Otrymano vid servera: %s\n", buf);

close(s);

printf("Client zavershyv robotu\n\n");

}

ДОДАТОК Г

Тексти програмsimpletcpserv та simpletcpclient

Лістинг 1

simpletcpserv:

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <stdio.h>

int main( void )

{

struct sockaddr_in local;

int s;

int s1;

int rc;

char buf[ 1 ];

local.sin_family = AF_INET;

local.sin_port = htons( 7500 );

local.sin_addr.s_addr = htonl( INADDR_ANY );

s = socket( AF_INET, SOCK_STREAM, 0 );

if ( s < 0 )

{

perror( "socket call failed" );

exit( 1 );

}

rc = bind( s, ( struct sockaddr * )&local, sizeof( local ) );

if ( rc < 0 )

{

perror( "bind call failed" );

exit( 1 );

}

rc = listen( s, 5 );

if ( rc )

{

perror( "listen call failed" );

exit( 1 );

}

s1 = accept( s, NULL, NULL );

if ( s1 < 0 )

{

perror( "accept call failed" );

exit( 1 );

}

rc = recv( s1, buf, 1, 0 );

if ( rc <= 0 )

{

perror( "recv call failed" );

exit( 1 );

}

printf( "%c\n", buf[ 0 ] );

rc = send( s1, "2", 1, 0 );

if ( rc <= 0 )

perror( "send call failed" );

exit( 0 );

}

simpletcpclient:

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdio.h>

int main( void )

{

struct sockaddr_in peer;

int s;

int rc;

char buf[ 1 ];

peer.sin_family = AF_INET;

peer.sin_port = htons( 7500 );

peer.sin_addr.s_addr = inet_addr( "127.0.0.1");

s = socket( AF_INET, SOCK_STREAM, 0 );

if ( s < 0 )

{

perror( "socket call failed" );

exit( 1 );

}

rc = connect( s, ( struct sockaddr * )&peer, sizeof( peer ) );

if ( rc )

{

perror( "connect call failed" );

exit( 1 );

}

rc = send( s, "1", 1, 0 );

if ( rc <= 0 )

{

perror( "send call failed" );

exit( 1 );

}

rc = recv( s, buf, 1, 0 );

if ( rc <= 0 )

perror( "recv call failed" );

else

printf( "%c\n", buf[ 0 ] );

exit( 0 );

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]