Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
практична робота 10.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
196.1 Кб
Скачать

Вживання інтерфейсу мережних викликів для інших сімейств протоколів. Unix Domain протоколи. Файли типу "сокет"

Розглянутий нами інтерфейс уміє працювати не тільки із стеком протоколів TCP/IP, але і з іншими сімействами протоколів. При цьому потрібна лише незначна зміна написаних з його допомогою програм. Розглянемо дії, які необхідно виконати для модернізації написаних для TCP/IP програм під інше сімейство протоколів.

  1. Змінюється тип сокета, тому для його точної специфікації потрібно задавати інші параметри в системному виклику socket().

  2. В різних сімействах протоколів застосовуються різні адресні простори для видалених і локальних адрес сокетів. Тому міняється склад структури для зберігання повної адреси сокета, назва її типу, найменування полів і спосіб їх заповнення.

  3. Опис типів даних і приречених констант знаходитиметься в інших include-файлах, тому буде потрібно замінити include-файли <netinet/in.h> і <arpa/inet.h> на файли, що відносяться до вибраного сімейства протоколів.

  4. Може змінитися спосіб обчислення фактичної довжини повної адреси сокета і вказівки його максимального розміру.

Мал. 15-16.9.  Схема роботи TCP-серверу з паралельною обробкою запитів

Давайте докладніше розглянемо ці зміни на прикладі сімейства UNIX Domain протоколів. Сімейство UNIX Domain протоколів призначено для спілкування локальних процесів з використанням інтерфейсу системних викликів. Воно містить один потоковий і один датаграмний протокол. Ніякий мережний інтерфейс при цьому не використовується, а вся передача інформації реально відбувається через адресний простір ядра операційної системи. Багато програм, що взаємодіють і з локальними, і з видаленими процесами (наприклад, X-Windows), для локального спілкування використовують цей стек протоколів.

Оскільки спілкування відбувається в рамках однієї обчислювальної системи, в повній адресі сокета його видалена частина відсутня. Як адресний простір портів – локальної частини адреси – вибрано адресний простір, співпадаючий з безліччю всіх допустимих імен файлів у файловій системі.

При цьому як ім'я сокета вимагається задавати ім'я неіснуючого ще файлу в директорії, до якої у вас є права доступу як на запис, так і на читання. При настройці адреси (системний виклик bind()) під цим ім'ям буде створений файл типу "сокет" – останній ще невідомий нам тип файлу. Цей файл для сокетів грає роль файлу-мітки типа FIFO для іменованих pip’ов. Якщо на вашій машині функціонують X-Windows, то ви зможете знайти такий файл в директорії з ім'ям /tmp/.X11-unix – це файл типу "сокет", що служить для взаємодії локальних процесів з віконним сервером.

Для зберігання повної адреси сокета використовується структура наступного вигляду, описаного у файлі <sys/un.h>:

struct sockaddr_un{

short sun_family;

/* Вибране сімейство

протоколів – завжди AF_UNIX */

char sun_path[108];

/* Ім'я файлу типу "сокет" */

};

Вибране ім'я файлу ми копіюватимемо всередину структури, використовуючи функцію strcpy().

Фактична довжина повної адреси сокета, що зберігається в структурі з ім'ям my_addr, може бути обчислена таким чином: sizeof(short)+strlen(my_addr.sun_path). В Linux для цих цілей можна використовувати спеціальний макрос мови З

SUN_LEN(struct sockaddr_un*)

Нижче приведені тексти переписаних під сімейство UNIX Domain протоколів клієнта і серверу для сервісу echo (програми 15–16-5.c і 15–16-6.c), що спілкуються через датаграми. Клієнт використовує сокет з ім'ям AAAA в поточній директорії, а сервер – сокет з ім'ям BBBB. Як випливає з опису типу даних, ці імена (повні або відносні) не повинні по довжині перевищувати 107 символів. Коментарі дані лише для змін в порівнянні з програмами 15–16-1.c і 15–16-2.c.

/* А simple echo UNIX Domain datagram server */

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h> /* Новий include-файл замість netinet/in.h і arpa/inet.h */

#include <string.h>

#include <stdio.h>

#include <errno.h>

#include <unistd.h>

int main()

{

int sockfd;

int clilen, n;

char line[1000];

struct sockaddr_un servaddr, cliaddr; /* новий тип даних під адреси сокетів */

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

/* Змінений тип сімейства протоколів */

{

реrror(NULL);

exit(1);

}

bzero(&servaddr, sizeof(servaddr));

servaddr.sun_family = AF_UNIX; /* Змінений тип сімейства протоколів і ім'я поля в структурі */

strcpy(servaddr.sun_path,"BBBB"); /* Локальний адреса сокета серверу – BBBB – в поточній директорії */

if(bind(sockfd (struct sockaddr *) &servaddr

SUN_LEN(&servaddr)) < 0) /* Змінено обчислення фактичної довжини адреси */

{

реrror(NULL);

close(sockfd);

exit(1);

}

while(1){

clilen = sizeof(struct sockaddr_un); /* Змінено обчислення максимальної довжини для адреси клієнта */

if((n = recvfrom(sockfd, line, 999, 0

(struct sockaddr *) &cliaddr &clilen)) < 0){

реrror(NULL);

close(sockfd);

exit(1);

}

if(sendto(sockfd, line, strlen(line), 0

(struct sockaddr *) &cliaddr, clilen) < 0){

реrror(NULL);

close(sockfd);

exit(1);

}

}

return 0;

}

Лістинг 15-16.5. Програма 15–16-5.c . А simple echo UNIX Domain datagram server

/* А simple echo UNIX Domain datagram client */

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h> /* Новий include-файл замість netinet/in.h і arpa/inet.h */

#include <string.h>

#include <stdio.h>

#include <errno.h>

#include <unistd.h>

int main() /* Аргументи командного рядка не потрібні оскільки сервіс є локальним, і не потрібно указувати, до якої машини ми поводимося із запитом */

{

int sockfd;

int n, len;

char sendline[1000], recvline[1000];

struct sockaddr_un servaddr, cliaddr; /* новий тип даних під адреси сокетів */

if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) /* Змінений тип сімейства протоколів */

{

реrror(NULL);

exit(1);

}

bzero(&cliaddr, sizeof(cliaddr));

cliaddr.sun_family= AF_UNIX; /* Змінений тип сімейства протоколів і ім'я поля в структурі */

strcpy(cliaddr.sun_path,"AAAA");/* Локальна адреса сокета клієнта – AAAA – в поточній директорії */

if(bind(sockfd (struct sockaddr *) &cliaddr SUN_LEN(&cliaddr)) < 0) /* Змінено обчислення фактичної довжини адреси */

{

реrror(NULL);

close(sockfd);

exit(1);

}

bzero(&servaddr, sizeof(servaddr));

servaddr.sun_family = AF_UNIX; /* Змінений тип сімейства протоколів і ім'я поля в структурі */

strcpy(servaddr.sun_path,"BBBB"); /* Локальна адреса сокета серверу – BBBB – в поточній директорії */

printf("String => ");

fgets(sendline, 1000, stdin);

if(sendto(sockfd, sendline, strlen(sendline)+1 0 (struct sockaddr *) &servaddr SUN_LEN(&servaddr)) < 0) /* Змінено обчислення фактичної довжини адреси */

{

реrror(NULL);

close(sockfd);

exit(1);

}

if((n = recvfrom(sockfd, recvline, 1000, 0 (struct sockaddr *) NULL, NULL)) < 0){

реrror(NULL);

close(sockfd);

exit(1);

}

recvline[n]= 0;

printf("%s", recvline);

close(sockfd);

return 0;

}

Лістинг 15-16.6. Програма 15–16-6.c . А simple echo UNIX Domain datagram client.

Наберіть програми, відкомпілюйте їх і переконайтеся в працездатності.