— Привіт, Аміго!

— Тема цієї лекції – Сокети. Socket у перекладі з англійської – це розетка.

Ти вже знаєш, що в кожного комп'ютера в мережі є унікальна IP-адреса.

— Ага.

— Уяви собі, що в тебе є кілька комп'ютерів, і на кожному з них запущено близько десятка програм, які працюють з інтернетом: Slack, Telegram тощо.

І ці програми хочуть спілкуватися між собою.

Треба зробити так, щоб вони один одному не заважали. Щоб Slack зв'язувався зі Slack’ом, Telegram з Telegram'ом тощо.

Пам'ятаєш, як цю проблему вирішили з URL та веб-серверами?

— Ага, додали порти.

— Саме так.

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

Так ось, IP-адреса – це унікальний номер комп'ютера, а IP-адреса+порт – це унікальний номер певної «квартири» (комірки) у комп'ютері, яку може зайняти програма.

Ось такий унікальний осередок і носить назву сокет.

У сокета є унікальний номер, і складається він з IP-адреси та номера порту.

— Ага. Тобто сокет – це номер певної віртуальної комірки в комп'ютері, яку може займати програма? А інша програма буде надсилати їй у цей осередок (комірку) повідомлення, і таким чином вони будуть спілкуватися?

— Не знаю, як ти це зрозумів, але саме так і є.

— Це моя робоінтуіція підказала.

— Чудово. Тоді давай поговоримо про деякі подробиці.

Сокети – це фактично найбільш базовий і найпримітивніший спосіб міжмережевої взаємодії програм.

У Java для роботи з сокетами є два класи. Це класи Socket і ServerSocket.

ServerSocket – це спеціальний клас, об'єкти якого виконують роль сервера. Тобто можуть обслуговувати запити, які прийшли на певний сокет.

Клас Socket – це фактично Socket-клієнт. За допомогою нього ми можемо надіслати повідомлення певному сокету та отримати відповідь.

Як надіслати повідомлення певному сокету:

Приклад
//створюємо сокет
Socket clientSocket = new Socket("localhost", 4444);

//отримуємо OutputStream
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream, true);
out.println("Kiss my shiny metal ass!");
out.flush();

//читаємо відповідь
InputStream inputStream = clientSocket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
String answer = in.readLine();

— Все дуже нагадує завантаження файлу з інтернету.

— Це тому що там теж використовуються сокети.

Сокети використовуються в основі всього, що пов'язане з мережею, ну або майже всього.

Ось тут можеш почитати додаткову інформацію.

— Дякую за лекцію.

— Але це ще не все!

Тепер ми розберемося, як працює серверний сокет.

Він працює трохи складніше.

Приклад
//створюємо об'єкт сервер-сокет
ServerSocket serverSocket = new ServerSocket(4444); //порт

//у циклі обробляємо вхідні з'єднання.
while (true)
{
 //метод accept чекає, поки хтось не під'єднається.
 Socket socket = serverSocket.accept();

 //читаємо повідомлення
 InputStream inputStream = socket.getInputStream();
 BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
 String message = in.readLine();

 //вигадуємо відповідь - просто розвертаємо рядок задом наперед
 String reverseMessage = new StringBuilder(message).reverse().toString();

 //надсилаємо відповідь
 OutputStream outputStream = socket.getOutputStream();
 PrintWriter out = new PrintWriter(outputStream, true);
 out.println(reverseMessage);
 out.flush();
}

Зверни увагу на декілька моментів.

Момент 1: Для створення сокету потрібно вказувати IP-адресу (або домен) та порт. Для створення серверного сокету — лише порт. Серверний сокет з'являється лише на тому комп'ютері, де його створили.

Момент 2: У класі ServerSocket є метод accept(), який, якщо його викликати, чекатиме на вхідне з'єднання. Тобто метод буде виконуватися нескінченно довго, доки якийсь клієнтський сокет не спробує звернутися до нього. Тоді метод accept() прийме з'єднання, створить об'єкт сокет для комунікації, а після цього поверне цей об'єкт.

З точки зору Java-програміста, сокет – це два потоки: InputStream, з якого можна читати повідомлення/дані, та OutputStream, куди можна писати повідомлення/дані.

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

Ось тобі цікавий приклад, можеш спробувати розібрати його і виконати.

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

— Ого! Вебсервер? Круто! Я вивчу його дуже уважно.

Дякую!

— Будь ласка, можеш іти відпочити!