- •Практичне заняття 10
- •Сокети (sockets) в unix і основи роботи з ними.
- •Системні виклики sendto() і recvfrom()
- •Визначення ip-адрес для обчислювального комплексу
- •Приклад програми udp-клієнта
- •Приклад програми udp-серверу
- •Організація зв'язку між процесами за допомогою установки логічного з'єднання
- •Встановлення логічного з'єднання. Системний виклик connect()
- •Приклад програми tcp-клієнта
- •Як відбувається встановлення віртуального з'єднання
- •Системний виклик listen()
- •Системний виклик accept()
- •Приклад простого tcp-серверу
- •Вживання інтерфейсу мережних викликів для інших сімейств протоколів. Unix Domain протоколи. Файли типу "сокет"
Встановлення логічного з'єднання. Системний виклик connect()
Серед системних викликів з боку клієнта з'являється тільки один новий – connect(). Системний виклик connect() при роботі з TCP-сокетами служить для встановлення логічного з'єднання з боку клієнта. Виклик connect() приховує усередині себе настройку сокета на вибраний системою порт і довільний мережний інтерфейс (по суті справи, виклик bind() з нульовим номером порту і IP-адресою INADDR_ANY). Виклик блокується до тих пір, поки не буде встановлено логічне з'єднання, або поки не пройде певний проміжок часу, який може регулюватися системним адміністратором.
Для встановлення з'єднання необхідно задати три параметри: дескриптор активного сокета, через який встановлюватиметься з'єднання, повну адресу сокета серверу і його довжину.
Системний виклик connect()
Прототип системного виклику
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockd
struct sockaddr *servaddr
int addrlen);
Опис системного виклику
Системний виклик connect служить для організації зв'язку клієнта з сервером. Частіше за все він використовується для встановлення логічного з'єднання, хоча може бути застосований і при зв'язку за допомогою датаграм (connectionless). Даний опис не є повним описом системного виклику, а призначено тільки для використовування в нашому курсі. Повну інформацію можна знайти в UNIX Manual.
Параметр sockd є дескриптором створеного раніше комунікаційного вузла, тобто значенням, яке повернув системний виклик socket().
Параметр servaddr є адресою структури, що містить інформацію про повну адресу сокета серверу. Він має тип покажчика на структуру-шаблон struct sockaddr, яка повинна бути конкретизована залежно від сімейства протоколів, що використовується, і заповнена перед викликом.
Параметр addrlen повинен містити фактичну довжину структури, адреса якої передається як другий параметр. Ця довжина міняється в зависмости від сімейства протоколів і розрізняється навіть в межах одного сімейства протоколів (наприклад, для UNIX Domain).
При встановленні віртуального з'єднання системний виклик не повертається до його встановлення або до закінчення встановленого в системі часу – timeout. При використовуванні його в connectionless зв'язку виклик повертається негайно.
Значення, що повертається
Системний виклик повертає значення 0 при нормальному завершенні і негативне значення, якщо в процесі його виконання виникла помилка.
Приклад програми tcp-клієнта
Розглянемо приклад – програму 15–16-3.с. Це простий TCP-клієнт, що звертається до стандартного системного сервісу echo. Стандартний сервіс приймає від клієнта текстову датаграму і, не змінюючи її, відправляє назад. За сервісом зарезервований номер порту 7. Помітимо, що це порт 7 TCP – не плутати з портом 7 UDP з прикладу в розділі "Приклад програми UDP-клієнта"! Для правильного запуску програми необхідно вказати символьну IP-адресу мережного інтерфейсу комп'ютера, до сервісу якого вимагається звернутися, як аргумент командного рядка, наприклад:
a.out 192.168.253.12
Для того, щоб підкреслити, що після встановлення логічного з'єднання клієнт і сервер можуть обмінюватися інформацією неодноразово, клієнт тричі запрошує текст з екрану, посилає його серверу і друкує одержану відповідь. Нижче представлений текст програми.
/* Простий приклад TCP-клієнта для сервісу echo */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
void main(int argc, char **argv)
{
int sockfd; /* Дескриптор сокета */
int n; /* Кількість переданих або прочитаних символів */
int i; /* Лічильник циклу */
char sendline[1000],recvline[1000]; /* Масиви для посиланого і прийнятого рядка */
struct sockaddr_in servaddr; /* Структура для адреси серверу */
/* Спочатку перевіряємо наявність другого аргументу в командному рядку. При його відсутності припиняємо роботу */
if(argc != 2){
printf("Usage: a.out <IP address>\n");
exit(1);
}
/* Обнуляємо символьні масиви */
bzero(sendline,1000);
bzero(recvline,1000);
/* Створюємо TCP сокет */
if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0){
реrror(NULL); /* Друкуємо повідомлення про помилку */
exit(1);
}
/* Заповнюємо структуру для адреси серверу: сімейство протоколів TCP/IP, мережний інтерфейс – з аргументу командного рядка, номер порту 7. Оскільки в структурі міститься додаткове не потрібне нам поле яке повинне бути нульовим, перед заповненням обнуляємо її всю */
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(51000);
if(inet_aton(argv[1], &servaddr.sin_addr)== 0){
printf("Invalid IP address\n");
close(sockfd);
exit(1);
}
/* Встановлюємо логічне з'єднання через створений сокет з сокетом серверу, адреса якого ми занесли структуру */
if(connect(sockfd (struct sockaddr *) &servaddr
sizeof(servaddr)) < 0){
реrror(NULL);
close(sockfd);
exit(1);
}
/* Три рази в циклі вводимо рядок з клавіатури, відправляємо її серверу і читаємо одержану відповідь */
for(i=0; i<3; i++){
printf("String => ");
fflush(stdin);
fgets(sendline, 1000, stdin);
if( (n = write(sockfd, sendline
strlen(sendline)+1)) < 0){
реrror("Can\'t write\n");
close(sockfd);
exit(1);
}
if ( (n = read(sockfd,recvline, 999)) < 0){
реrror("Can\'t read\n");
close(sockfd);
exit(1);
}
printf("%s", recvline);
}
/* Завершуємо з'єднання */
close(sockfd);
}
Лістинг 15-16.3. Програма 15–16-3.c . Простий приклад TCP-клієнта для сервісу echo.
Наберіть і відкомпілюйте програму. Перед запуском "взнайте у свого системного адміністратора", чи запущений в системі стандартний TCP-сервіс echo і, якщо ні, попросіть це зробити. Запустіть програму із запитом до сервісу свого комп'ютера, до сервісів інших комп'ютерів. Якщо як IP-адреса вказати неіснуючу адресу або адресу вимкненої машини, то програма повідомить про помилку при роботі виклику connect() (правда, можливо, доведеться почекати закінчення timeout’а). При завданні адреси комп'ютера, на якому не працює сервіс echo, про помилку стане відомо зразу ж. Протокол TCP є надійним протоколом. Якщо логічне з'єднання встановити не вдалося, то відправник знатиме про це.
