Введення-виведення даних. Базові класи введення-виведення

Клас RandomAccessFile дозволяє організувати роботу з файлами в режимі прямого доступу, тобто вказувати зсув та розмір блока даних, над яким виконується операція введення-виведення.

Клас InputStreamє базовим для більшості класів, на основі яких створюються потоки введення. Саме ці похідні класи і використовується на практиці. Щодо InputStream – це абстрактний клас, який містить декілька корисних методів, а саме:

int read() – зчитує з вхідного потоку окремі байти як цілі числа та повертає –1, коли більше нема чого читати;

int read(byte b[]) – зчитує множину байтів в байтовий масив, повертаючи кількість реально введених байтів;

int read(byte b[], int off, int len) – також читає дані в байтовий масив, але дозволяє крім того задати ще зсув в масиві та максимальну кількість зчитаних байтів;

long skip(long n) – пропускає n байтів в потоці;

int available() – повертає кількість байтів, які є в потоці в даний момент;

void mark(int readlimit) – помічає поточну позицію в потоці, readlimit – кількість байтів, які можна прочитати з потоку до момента, коли помічена позиція втратить свою силу;

void reset() – повертається до поміченої позиції в потоці;

markSupported() – повертає бульове значення, яке вказує, чи можна в даному потоці відмічати позиції та повертатися до них;

void close() – закриває потік.

Як бачимо, список достатньо серйозний. З урахуванням того, що цей клас має аж шість прямих та чотири непрямих нащадки, детальне вивчення потокового введення потребує багато часу. Але ми нічого не сказали про ще один метод – про конструктор. Хоча саме тут немає нічого цікавого – він без параметрів, та й клас абстрактний.

Клас OutputStreamутворює пару до класу InputStream. Основні методи:

void write(byte b)

void write(byte b[])

void write(byte b[], int off, int len)

void close()

void flush() – виконує примусовий запис всіх буферизованих вихідних даних.

Клас RandomAccessFile дозволяє організувати роботу з файлами в режимі прямого доступу, тобто вказувати зсув та розмір блока даних, над яким виконується операція введення-виведення.

Клас Fileпризначений для роботи з заголовками каталогів та файлів. За допомогою цього класу можна отримати список файлів та каталогів, розташованих в заданому каталозі, створити або вилучити каталог, перейменувати файл або каталог і т. д.

За допомогою класа FileDescriptorможна перевірити ідентифікатор відкритого файла.

Клас StreamTokenizer дозволяє організувати виділення з вхідного потоку даних елементів, що відділяються один від іншого заданими розділювачами.

  1. Дати порівняльну характеристику протоколів стеку TCP/IP та UDP.

IP – це протокол мережного рівня, який визначає куди саме будуть передаватись дані. IP характеризується як ненадійний протокол, тому що він не знаходить помилок і не виконує повторне пересилання даних. Що таке IP- та DNS-адреса можна прочитати в [2].

Протоколи TCP та UDP відносяться до транспортного рівня. Протокол TCP забезпечує надійний зв’язок на основі логічного з’єднання з неперервним потоком даних. Доставка TCP-пакета схожа з доставкою листа за замовленням.

З неперервним потоком даних. TCP забезпечує механізм передачі, що дозволяє пересилати довільну кількість байтів. Дані нарізаються на сегменти певної довжини, завдяки чому для рівня додатків емулюється неперервний потік даних.

На основі логічного з’єднання. Перед початком передачі даних TCP встановлює з віддаленою машиною з’єднання, обмінюючись службовою інформацією. Цей процес носить назву handshaking – рукостистискання. Комп’ютери домовляються між собою про основні параметри зв’язку.

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

Доставка UDP-пакета схожа з доставкою поштової картки, яку кидають у скриньку сподіваючись, що хтось її звідти рано чи пізно дістане.

Протокол UDP має такі характеристики:

Оснований на повідомленнях. UDP дозволяє додаткам пересилати інформацію у вигляді повідомлень (дейтаграм), які є одиницями передачі даних в UDP. Розподіл даних по окремим дейтаграмам має виконувати сам додаток.

Без встановлення логічного з’єднання. Ніякого обміну службовою інформацією на початку з’єднання. Інформація передається в припущенні, що приймальна сторона її очікує.

Ненадійний. UDP не має ані вбудованого механізму знаходження помилок, ані повторного пересилання спотворених або втрачених даних.

Як бачите, майже все говорить на користь TCP. Тоді для чого ж нам UDP, запитаєте Ви. Може тому що програмісту непросто реалізувати усі ті плюси, які ми виставили TCP? Навпаки, все це вже реалізовано і все це у нас є. Але справа в тому, що чудовий TCP потребує великих додаткових витрат, а це не завжди виправдано. Приклад використання UDP – служба часу.

  1. Створення сокетів TCP

У бібліотеці класів Java є дуже зручний засіб, за допомогою якого можна організувати взаємодію між додатками Java і аплетами, що працюють як на одному і тому ж, так і на різних вузлах мережі TCP/IP. Це засіб, що народився в світі операційної системи UNIX, – так звані сокети (sockets).

Що таке сокети? Можна уявити собі сокети у вигляді двох розеток, в які включений кабель, призначений для передачі даних через мережу. Переходячи до комп'ютерної термінології, скажімо, що сокети – це програмний інтерфейс, призначений для передачі даних між додатками.

Перш ніж додаток зможе виконувати передачу або прийом даних, він повинен створити сокет, вказавши при цьому адресу вузла IP, номер порту, через який передаватимуться дані, і тип сокета.

З адресою вузла IP ми вже стикалися. Номер порту служить для ідентифікації додатку. Зауважимо, що існують так звані "добре відомі" (well known) номери портів, зарезервовані для різних додатків. Так, порт з номером 80 зарезервований для використання серверами Web при обміні даними через протокол HTTP.

Що ж до типів сокетів, то їх два – потокові і датаграмні.

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

- вхідними або вихідними,

- звичними або форматованими,

- з використанням або без використання буферизації.

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

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

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

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

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

Сокет (socket) –це описувач мережного з’єднання. Сокет TCP використовує протокол TCP, успадковуючи всі характеристики цього протоколу. Для створення сокета TCP необхідно мати таку інформацію:

- IP-адреси клієнта та сервера;

- порти, які використовують додатки на клієнтському та серверному боці.

Сервер – це комп’ютер, який очікує звертань від різних машин з запитом конкретних ресурсів. Відповідно клієнти – це комп’ютери які звертаються з цими запитами до сервера. Не слід думати, що сервер – це головний, а клієнт – це підлеглий. В принципі і клієнт, і сервер – рівноправні в тому сенсі, що і той, і інший можуть і пересилати, і отримувати дані. Але щоб відбулась телефонна розмова хтось має подзвонити (клієнт), а хтось має чергувати біля телефону і своєчасно зняти слухавку (сервер).

Щоб почати обмін через сокет, додаток-клієнт має прив’язатися до конкретного порта. Порт – це абстракція (до речі, як і сокет), яка дозволяє розділити різні додатки, що можуть входити до мережі з одного і того самого комп’ютера. Іншими словами, уявіть ситуацію, коли в багатозадачній системі з одного комп’ютера різні програми шлють запити і очікують відповіді. Як відрізнити, кому яка відповідь призначена? Щоб уникнути плутанини, різні додатки мають прив’язуватися до різних портів.

Ось ми і плавно переходимо від теорії до практики. Хто і як має визначати номери портів? Відповідь – сервер, а він має знати, як розподіляються номери портів. За загальноприйнятими погодженнями, це мають бути номери, більші за 1024.

Наши рекомендации