Розробка клієнт-серверного чату на java
Короткий опис
На даний момент закінчую 2-й курс універститету, однією з лабораторних робіт по курсу Java було написання чату. Після того, як розібрався в темі сокетов, сериализации об'єктів і MVC, хотілося б поділитися з Новомосковсктелім, тим більше, що воно мені невимовно допомогло при написанні проекту.
Ну і, зрозуміло, врахую всі помилки і недоліки, які будуть озвучені.
трохи теорії
Отже, для початку. Проект складатиметься з двох частин: клієнта і сервера. Клієнт матиме GUI, написаний за допомогою бібліотеки Swing. Сервер GUI мати не буде, тільки log-файл і невеликий висновок в консоль.
Для написання чату, нам знадобляться деякі знання.
Оскільки взаємозв'язок клієнта і сервера у нас буде реалізована за допомогою сокетів, познайомимося з ними ближче.
Сокети (англ. Socket - поглиблення, гніздо, роз'єм) - назва програмного інтерфейсу для забезпечення обміну даними між процесами. Сокет - абстрактний об'єкт, який представляє кінцеву точку з'єднання.
Кожен процес може створити слухає сокет (серверний сокет) і прив'язати його до якого-небудь порту операційної системи. Хто слухає процес зазвичай знаходиться в циклі очікування, тобто прокидається при появі нового з'єднання.
Для нас це означає, що сервер буде слухати будь-якої порт (для більшої універсальності, ми будемо ставити порт в конфігураційному файлі) і після підключення клієнта, будемо виробляти з ним якісь дії.
Передача об'єктів по мережі
Не будемо говорити про плюси і мінуси кожного підходу. Скористаємося другим варіантом. (А якщо знадобиться, коли-небудь потім, я напишу другий)
Отже, що таке сериализация об'єктів.
Серіалізация - процес перекладу будь-якої структури даних в послідовність бітів. Зворотною до операції сериализации є операція десеріалізациі - відновлення початкового стану структури даних з бітової послідовності.
Серіалізация використовується для передачі об'єктів по мережі і для збереження їх у файли.
В Java єдине, що потрібно для сериализации об'єкта - імплементувати інтерфейс Serializable, який є інтерфейсом-маркером, тобто не містить методів.
пишемо Сервер
Отже, короткий опис роботи сервера.
Сервер працює у вічному циклі. Як тільки підключається новий клієнт, він створює для роботи з ним новий потік, сповіщає вже підключених клієнтів про новий користувачів, а новачкові відсилає якусь кількість останніх повідомлень в чаті. Клієнт же, при підключенні повідомляє про себе деяку інформаціію, а також якесь повідомлення, яке ідентифікує те, що він тільки що підключився.
Але крім цього, треба не забути про те, що клієнти можуть і відключатися. Тобто ми періодично повинні обмінюватися з клієнтами сигналами (ping'овать один одного), щоб у разі відключення клієнта (або сервера) все про це дізналися.
Отже, приступимо. Створимо наш перший клас
Ах да, ми ж хотіли отримувати номер порту з конфігураційного файлу. Створимо для конфіга окремий клас, в якому будемо зберігати статичні поля - параметри нашого чату.
Найзручніше зберігати параметри в properties-файлі, благо Java надає зручний інтерфейс для роботи з ними.
Отже, наш properties-файл буде складатися всього з одного рядка (поки що)
PORT = 1234
Вся завантаження параметрів відбувається в блоці статичної ініціалізації, оскільки повноцінний конструктор в нашому випадку - недозволена розкіш.
Залишилося тільки замінити в Server.java
ServerSocket socketListener = new ServerSocket ( "тисячі двісті тридцять чотири"); на ServerSocket socketListener = new ServerSocket (Config.PORT); і додати потрібні import'и
Надалі, import'и в коді буду випускати, оскільки будь-яка IDE їх сама підставить.
Отже, ми написали new ClientThread () ;. Але що це таке, поки не вирішили. Пора виправити це.
Цей клас у нас буде відповідати за прийом і передачу повідомлень між клієнтом і сервером, а значить, найголовніший клас в чаті - саме ClientThread.
Оскільки він працює в окремому потоці, перше, що ми повинні зробити - написати
А тепер подумаємо, що ж написати в методі run ().
Отже, по порядку. Для початку, ми повинні отримати від клієнта інформацію «Ти хто такий?» В іншому випадку - «Давай, до побачення!». Як тільки ми дізналися хто він такий, ми повинні відправити йому останні повідомлення в нашому чаті.
Далі, періодично, ми повинні його ping'овать його якимось запитом, щоб переконатися, що не ведемо спілкування з трупом.
Потім, ми повинні отримувати від нього повідомлення, про які повинні повідомляти всіх підключених клієнтів.
Ну і, як тільки ми перестали отримувати від нього запити - клієнта слід видалити зі списку доступнх користувачів.
На час забудемо про ClientThread, а замислимося «Яким чином буде відбуватися спілкування?»
Ми вже вирішили, що будемо передавати серіалізовані об'єкт. Отже, чтоже має бути в цьому об'єкті?
Я зупинився на наступному варіанті:
1. Логін користувача, що відправив це повідомлення (або Server-Bot)
2. Власне, саме повідомлення
3. Час відправки
4. Список доступних сервера клієнтів (для відображення у користувача)
Для успішної сериализации / десеріалізациі, клас в клієнті і сервері повинен бути однаковим. Тому подбаємо відразу і про те, і про інше.
Думаю, все очевидно. Також, крім повідомлень ми хочемо передавати щось на зразок ping'ов.
Может кому пригодится клієнт :)
Написав його за пару годин, і досвіду в роботі з потоками немає, тому не чіпляйтеся.
Всього в проекті 4 файлу:
private static String userName = «»;
static Socket socket = null;
public static void main (String [] args) System.out.println ( «Вас вітає клієнт чату! \ n");
System.out.println ( «Введіть свій нік і натисніть \" Enter \ »»);
// Створюємо потік для читання з клавіатури
BufferedReader keyboard = new BufferedReader (new InputStreamReader (System.in));
try // Чекаємо поки користувач введе свій нік і натисне кнопку Enter
userName = keyboard.readLine ();
System.out.println ();
> Catch (IOException e)
// Беремо вхідний і вихідний потоки сокета, тепер можемо отримувати і відсилати дані клієнтом
InputStream inputStream = socket.getInputStream ();
OutputStream outputStream = socket.getOutputStream ();
// Конвертуємо потоки в інший тип, щоб легше обробляти текстові повідомлення
ObjectOutputStream objectOutputStream = new ObjectOutputStream (outputStream);
ObjectInputStream objectInputStream = new ObjectInputStream (inputStream);
new PingThread (objectOutputStream, objectInputStream);
// Створюємо потік для читання з клавіатури
String message = null;
System.out.println ( «Наберіть повідомлення і натисніть \" Enter \ "\ n");
while (true) / Бесконечный цикл
message = keyboard.readLine (); // чекаємо поки користувач введе щось і натисне кнопку Enter.
objectOutputStream.writeObject (new Message (userName, message)); // відсилаємо введений рядок тексту сервера.
>
> Catch (Exception e)
>
finally try if (socket! = null)
> Catch (IOException e)
>
>
>
public class ServerListenerThread implements Runnable private Thread thread = null;
private ObjectOutputStream objectOutputStream = null;
private ObjectInputStream objectInputStream = null;
public ServerListenerThread (ObjectOutputStream objectOutputStream, ObjectInputStream objectInputStream) this.objectOutputStream = objectOutputStream;
this.objectInputStream = objectInputStream;
thread = new Thread (this);
thread.start ();
>
@Override
public void run () try while (true) Message messageIn = (Message) objectInputStream.readObject ();
if (messageIn instanceof Ping) Ping ping = (Ping) messageIn;
objectOutputStream.writeObject (new Ping ());
> Else System.out.println ( «[» + messageIn.getDate (). ToString () + »]» + messageIn.getLogin () + ».» + MessageIn.getMessage ());
>
>
>
catch (SocketException e)
catch (ClassNotFoundException e)
catch (IOException e)
>
>
3, 4) Це файлу протоколу обміну з сервером: Message.java і Ping.java
Власне ось і весь клієнт. А далі вже самі нарощуйте функціонал і придумуйте GUIню яку хочете)