Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Робота з потоковими сонетами
Тут розглядатимуться головні системні виклики, які використовують під час розробки серверів та клієнтів з використанням потокових сокетів на основі протоколу TCP (рис. 16.4). Це - основний вид сокетів, що найчастіше трапляється в реальних застосуваннях.
Зв'язування сокета з адресою Сокет, дескриптор якого повернутий викликом socket О, не пов'язаний із конкретною адресою і недоступний для клієнтів. Для пов'язування сокета з адресою необхідно використати системний виклик bind():
int bind(int sockfd. const struct sockaddr *pmy_addr. socklen_t alen): де: sockfd — дескриптор сокета, створений за допомогою socket(); pmyaddr — покажчик на заздалегідь заповнену структуру, що задає адресу сокета (наприклад, sockaddrin);
alen - розмір структури, на яку вказує pmyaddr.
Цей виклик повертає -1, якщо виникла помилка. Під час виконання bind О застосуванням-сервером необхідно задати наперед відомий порт, через який клієнти зв'язуватимуться з ним. Можна також вказати конкретну IP-адресу (при цьому допускатимуться лише з'єднання, для яких вона зазначена як адреса призначення), але найчастіше достатньо взяти довільну адресу локального хоста, скориставшись константою INADDRANY:
struct sockaddMn my_addr = { 0 }; int listenfd – socket(...); //... задача my_addr.sin_family i my_addr.sin_port my_addr.sin_addr.s_addr = INADDR_ANY; bind(listenfd. (struct sockaddr *)&my_addr. sizeof(my_addr)); Найпоширенішою помилкою під час виклику bind() є помилка з кодом EADDRI-NUSE, яка свідчить про те, що цю комбінацію «IP-адреса — номер порту» вже використовує інший процес. Часто це означає повторну спробу запуску того самого сервера.
if (binddistenfd....)== -1 && errno == EADDRINUSE) { printfC'noMMnKa, адресу вже використовують\п"); exit(-l); }
Щоб досягти гнучкості у вирішенні цієї проблеми, рекомендують дозволяти користувачам налаштовувати номер порту (задавати його у конфігураційному файлі, командному рядку тощо). Відкриття сокета для прослуховування За замовчуванням сокет, створений викликом socketO є клієнтським активним сокетом, за допомогою якого передбачають з'єднання із сервером (особливості використання таких сокетів розглянемо в наступному розділі). Щоб перетворити такий сокет у серверний прослуховувальний (listening), призначений для приймання запитів на з'єднання від клієнтів, необхідно використати системний виклик listen()
int listenCint sockfd. int backlog):
де: sockfd - дескриптор сокета, пов'язаний з адресою за допомогою bindO; backl og - задає довжину черги запитів на з'єднання, створеної для цього сокета. Фактично внаслідок виклику listen О створяться дві черги запитів: перша з них містить запити, для яких процес з'єднання ще не завершений, друга — запити, для яких з'єднання встановлене. Параметр backlog визначає сумарну довжину цих двох черг; для серверів, розрахованих на значне навантаження, рекомендують задавати достатньо велике значення цього аргументу:
listentlistenfd. 1024): Внаслідок виклику listen О сервер стає цілковито готовий до приймання запитів на з'єднання.
Прийняття з'єднань Спроба клієнта встановити з'єднання із сервером після виклику listenО має завершуватися успішно. Після створення нове з'єднання потрапляє у чергу встановлених з'єднань. Проте, для сервера воно залишається недоступним. Щоб отримати доступ до з'єднання, на сервері його потрібно прийняти за допомогою системного виклику acceptO:
int acceptant sockfd. struct sockaddr *cliaddr. socklen_t *addrlen); де: sockfd - дескриптор прослуховувального сокета; cliaddr - покажчик на структуру, у яку буде занесена адреса клієнта, що запросив з'єднання; addrlen - покажчик на змінну, котра містить розмір структури cliaddr.
Головною особливістю цього виклику є повернене значення — дескриптор нового сокета з'єднання (connection socket), який створений внаслідок виконання цього виклику і призначений для обміну даними із клієнтом. Прослуховувальний сокет після виконання accepte) готовий приймати запити на нові з'єднання.
struct sockaddMn their_addr = { 0 }; int listenfd. connfd, sin_size = sizeof(struct sockaddrin); // listenfd «sockett...). bindelistenfd....). 1 і sten( listenfd....) connfd = aeeepti listenfd. (struct sockaddr *)&their_addr. &sin_size); // використання connfd для обміну даними із клієнтом
Виклик acceptO приймає з'єднання, що стоїть першим у черзі встановлених з'єднань. Якщо вона порожня, процес переходить у стан очікування, де перебуватиме до появи нового запиту. Саме на цьому системному виклику очікують ітеративні та багатопотокові сервери, що використовують сокети. Такі сервери розглядатимемо далі в цьому розділі.
Задання з'єднань на клієнті Дотепер ми розглядали виклики, які мають бути використані на сервері. На клієнті ситуація виглядає інакше. Після створення сокета за допомогою socket () необхідно встановити для нього з'єднання за допомогою системного виклику connecte), після чого можна відразу обмінюватися даними між клієнтом і сервером. int connect(int sockfd. const_struct sockaddr *saddr. socklen_t alen); де: sockfd - сокет, створений за допомогою socketí); saddr — покажчик на структуру, що задає адресу сервера (IP-адресу віддаленого хоста, на якому запущено сервер і порт, який прослуховує сервер); alen - розмір структури saddr. Ось приклад створення з'єднання на клієнті: struct sockaddrJn their_addr - { 0 }; sockfd - sockett...); // заповнення their_addr.sin_family. their_addr.sin_port inet_aton("IP-aapeca-сервера". &(their_addr.sin_addr)); connectesockfd. (struct sockaddr *)&their_addr. sizeof(their_addr)); // обмін даними через sockfd У разі виклику connecte) починають створювати з'єднання. Повернення відбувається, якщо з'єднання встановлене або сталася помилка (при цьому поверненим значенням буде -1). Зазначимо, що, якщо connecte) повернув помилку, користуватися цим сокетом далі не можна, його необхідно закрити. Коли потрібно повторити спробу, створюють новий сокет за допомогою socket (). Клієнтові зазвичай немає потреби викликати binde) перед викликом connecte) -ядро системи автоматично виділяє тимчасовий порт для клієнтського сокета.
Закриття з'єднань Після використання всі з'єднання необхідно закривати. Для цього застосовують стандартний системний виклик close(): close(sockfd);
|
||||||
Последнее изменение этой страницы: 2017-02-06; просмотров: 176; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.145.93.221 (0.008 с.) |