Клієнт TCP

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Без мереж зараз нікуди, це вірно і для програміста і для железячнік. Стандартом де-факто в організації сучасних мереж став протокол TCP, розуміння якого ще на крок наблизить нас до професіоналів. До того ж, ознайомившись з принципами міжмережевого обміну даними і з'єднавши ці знання з нашими знаннями в області межпроцессное взаємодій ми зможемо писати цілком гідні програми. Передбачається, що ви вже маєте деякі розуміння в принципів організації мереж на базі TCP / IP. По крайней мере, ви повинні знати що таке доменне ім'я, IP-адресу і порт. Отже, приступимо.

Сервери та клієнти

Сокети бувають декількох типів: потокові і датаграмною. Датаграмною сокети не гарантують збереження переданих даних. Сокети цього типу підходять хіба що для обміну користувальницьким повідомленнями, тому загострювати увагу на них ми не будемо. Потокові сокети забезпечують надійний двосторонній обмін даними.

Робота з сокетами дуже схожа на роботу з каналами. Крім типів, сокети поділяються по областях дії: INET і UNIX. Область дії визначає метод ідентифікації сокета: для інтернет-сокетів це адреса хоста і номер порту, а для гнізд UNIX - ім'я файлу. Далі мова піде переважно про потокових інтернет-сокет.

У випадку з каналами ми просто пов'язували два дескриптора за допомогою функції pipe. Таким чином ми отримували односторонній канал зв'язку. У випадках, коли нам було необхідно забезпечити двосторонній зв'язок нам доводилося напружуватися трохи більше: створювати два канали, перевизначати потоки і т.п. Потокові сокети забезпечують двосторонній зв'язок. Тобто, ми можемо читати і писати з кожної сторони з'єднання. Але програмування сокетів дещо ускладнюється через можливість мережевого з'єднання. На відміну від каналів, сокети можуть створюватися на різних машинах з'єднаних мережею (підтримуючої протокол TCP / IP). Для того, що б як то позбутися невизначеності дій при створенні з'єднання введені такі поняття як сервер і клієнт. У контексті цієї статті сервером будемо називати процес, який створює сокет і очікує підключення клієнтів. Клієнти - це ті процеси, які намагаються ініціювати з'єднання з сервером. При цьому, не важливо на якій машині в мережі буде знаходитися клієнт: він може ініціювати з'єднання з сервером на локальній машині або на віддаленій.

Загалом, процес з'єднання можна розділити на кілька етапів. Насамперед, необхідно отримати ідентифікатор створюваного сокета (інакше - ім'я) незалежно від того, клієнт це або сервер. Далі, і клієнт і сервер повинні створити сокет з вказаним ім'ям. Після цього сервер переходить в режим очікування вхідних підключень, а клієнт виконує спробу підключення до сервера. У разі успішного проходження цих етапів ми маємо готове підключення: дескриптор читання / запису у сервера і аналогічний у клієнта. Тепер можна приступати до обміну даними. У процесі розбору принципів межпроцессное взаємодій ми вже стикалися з проблемою відкритих дескрипторів. Так ось, з сокетами те ж саме: не забувайте закривати дескриптори. Втім, ми напевно ще зіткнемося з цією проблемою, адже у нас попереду ціла купа підводних каменів, яку доведеться розгрібати при роботі з сокетами.

Простий приклад

Для початку розберемо простий приклад - отримання документа по протоколу HTTP. Існує спеціальний інтерфейс полегшує роботу з сокетами з Perl - IO:: Socket. Однак, ми не будемо використовувати IO:: Socket, так як ми бажаємо отримати максимальний контроль над з'єднанням. Хоча реально, використання IO:: Socket значно полегшує роботу з сокетами, та до того ж значно знижує ризик допустити помилку. При вирішенні реальних завдань я рекомендую використовувати IO:: Socket.

Отже, я назвав програму "gethttp.pl". Нам знадобиться модуль Socket, в якому реалізовані всі необхідні платформозавісімие функції. Перш за все, це стосується функції ідентифікації сокетів. Але, все по порядку.

#! / Usr / bin / perl-w

# Gethttp.pl

use Socket;

use strict;

unless ($ # ARGV == 1) {

die "Usage: gethttp.pl [host] [document] n";

}

my $ sock_name = GetSockName ($ ARGV [0], 80)

or die "Couldn't convert $ ARGV [0] into an Internet address: $! n";

socket (CONN, PF_INET, SOCK_STREAM, getprotobyname ('tcp'));

connect (CONN, $ sock_name)

or die "Couldn't 'connect to $ ARGV [0]: $! n";

print CONN "GET $ ARGV [1] HTTP/1.0n";

print CONN "Host: $ ARGV [0] nn";

my @ body =;

close (CONN);

print join ("",body);

Після підключення модуля Socket ми перевіряємо чи достатньо аргументів передано на вхід програми. Згідно з описом, запуск програми повинен аргументуватися двома значеннями: ім'ям хоста і віртуальним шляхом одержуваного документа. Так от, якщо масив вхідних аргументів не містить необхідних двох аргументів, тоді програма завершується.

Наступний крок виконує ідентифікацію сокета. Функція GetSockName () приймає в якості аргументу назву хоста (або його IP-адреса) і номер порту. Якщо комусь незрозумілий сенс термінів хост і порт, то можна провести таку аналогію: що б потрапити в гості до свого знайомого ви повинні знати номер будинку та номер квартири. Ось тут номер будинку - це IP-адреса комп'ютера, до якого здійснюється підключення, а квартира - номер порту.

Реалізація функції ідентифікації сокета на мій погляд дуже зручна, тому що приховує всі незрозумілості. До того ж, як я вже говорив, визначення імені сокета це обов'язковий процес як для сервера, так і для клієнта. З цього ми з легкістю зможемо використовувати функцію GetSockName () в наших наступних програмах.

Після ідентифікації сокета ми створюємо сокет за допомогою вбудованої функції socket (). В якості аргументів ця функція приймає дескриптор з'єднання (на замітку: звичайний файловий маніпулятор), константу, визначальну область дії сокета (PF_INET або PF_UNIX), константу, визначальну тип сокета (датаграмний або потоковий) і ідентифікатор протоколу. Ідентифікатор протоколу відповідає встановленому в системі визначається числовим значенням В.С допомогою функції getprotobyname ().

Після того, як сокет створений, ми намагаємося з'єднатися з віддаленим сервером. Робиться це за допомогою функції connect (), в якості аргументів якої приймається дескриптор і ідентифікатор сокета. У разі невдалої спроби з'єднання програма завершується з помилкою. Далі оператори print, які дотримуючись правил протоколу HTTP оголошують про необхідність видати зазначений документ. У масив @ body ми зберігаємо дані, отримані від сервера. Закриваємо з'єднання і виводимо вміст масиву @ body. Ось і наш документ.

Функція GetSockName

Тепер розберемо функцію GetSockName ().

sub GetSockName {

my ($ nm, $ pt) = @ _;

return undef unless defined ($ nm);

return undef unless defined ($ pt);

return undef unless $ nm = gethostbyname ($ nm);

return sockaddr_in ($ pt, $ nm);

}

Ось така нехитра функція рятує нас від головного болю при ідентифікації сокета. За допомогою функції gethostbyname () ми отримуємо IP-адреса хоста призначення. Інакше це називається дозволом імені. Функція sockaddr_in () входить до складу модуля Socket. У скалярному контексті sockaddr_in упаковує номер порту і адреса хоста в структуру SOCKADDR_IN.

Тепер давайте спробуємо, що ж у нас вийшло. Запускаємо програму і ... Ха-ха-ха. Що, знову зависли? Ну і де ж у нас помилка? Правильно, ми забули відключити буфферізацію. Дані як би відправлені, але їх занадто мало для заповнення буффера. Тому фактично, наші надіслані дані застрягли в сокеті. А сервер чекає і чекає, коли ж клієнт заявить про своє бажання. Давайте виправимо становище і додамо наступний код між рядків:

connect (CONN, $ sock_name)

or die "Couldn't 'connect to $ ARGV [0]: $! n";

select (CONN); $ | = 1; select (STDOUT);

print CONN "GET $ ARGV [1] HTTP/1.0n";

Ось тепер все має працювати.

Висновок

Наша програма, звичайно, не супер-пупер, але на дещо вона все-таки згодиться. Наприклад, якщо відділити заголовки відповіді від, безпосередньо, тіла відповіді, то можна завантажувати файли по HTTP. Давайте так і зробимо.

Як нам відомо, відповідь сервера складається із заголовка і тіла. При чому, заголовок відповіді відділяється від тіла двома перекладами рядка. Ось і знайдемо ці два переклади рядки:

print CONN "GET $ ARGV [1] HTTP/1.0n";

print CONN "Host: $ ARGV [0] nn";

my $ body = "";

$ Body .= $ _ while;

close (CONN);

$ Body = ~ s /^.+? nr? Nr? / / S;

print $ body;

Тепер ми можемо виконати команду:

[Root @ avalon scripts] #. / Gethttp.pl whirlwind.ru / index.cgi> index.html

для отримання HTML-коду індексного сторінки нашого сайту.

Ну і все, для початку. У вас вже достатньо навичок для метушні з протоколами високого рівня. От і спробуйте попрацювати з FTP, або SMTP.

Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Реферат
16.6кб. | скачати


Схожі роботи:
Дослідження протоколів TCP IP
Протокол надійної доставки повідомлень TCP
Соціальний працівник і клієнт
Клієнт і рекламне агентство
Система Клієнт-банк
Система Клієнт банк
Поштовий клієнт Outlook Express
Клієнт соціальної роботи типологія і класифікація
Структура апаратне забезпечення системи клієнт банк 2
© Усі права захищені
написати до нас