From 7a137e2797e448cfa885bd5029032be999c7e614 Mon Sep 17 00:00:00 2001 From: esoe Date: Sat, 17 Sep 2022 12:28:34 +0300 Subject: [PATCH] ready --- pom.xml | 75 +++++++++++ src/main/java/ru/molokoin/Server.java | 177 +++++++++++++++++++++++++ src/test/java/ru/molokoin/AppTest.java | 20 +++ 3 files changed, 272 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/ru/molokoin/Server.java create mode 100644 src/test/java/ru/molokoin/AppTest.java diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d37237a --- /dev/null +++ b/pom.xml @@ -0,0 +1,75 @@ + + + + 4.0.0 + + ru.molokoin + chat-server + 0.1 + + chat-server + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/src/main/java/ru/molokoin/Server.java b/src/main/java/ru/molokoin/Server.java new file mode 100644 index 0000000..62f1fd5 --- /dev/null +++ b/src/main/java/ru/molokoin/Server.java @@ -0,0 +1,177 @@ +package ru.molokoin; +import java.io.*; +import java.net.*; +import java.util.LinkedList; + +/** + * проект реализует консольный многопользовательский чат. + * вход в программу запуска сервера - в классе Server. + * @author izotopraspadov, the tech + * @version 2.0 + */ + +class ServerSomthing extends Thread { + + private Socket socket; // сокет, через который сервер общается с клиентом, + // кроме него - клиент и сервер никак не связаны + private BufferedReader in; // поток чтения из сокета + private BufferedWriter out; // поток завписи в сокет + + /** + * для общения с клиентом необходим сокет (адресные данные) + * @param socket + * @throws IOException + */ + + public ServerSomthing(Socket socket) throws IOException { + this.socket = socket; + // если потоку ввода/вывода приведут к генерированию искдючения, оно проброситься дальше + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); + Server.story.printStory(out); // поток вывода передаётся для передачи истории последних 10 + // сооюбщений новому поключению + start(); // вызываем run() + } + @Override + public void run() { + String word; + try { + // первое сообщение отправленное сюда - это никнейм + word = in.readLine(); + try { + out.write(word + "\n"); + out.flush(); // flush() нужен для выталкивания оставшихся данных + // если такие есть, и очистки потока для дьнейших нужд + } catch (IOException ignored) {} + try { + while (true) { + word = in.readLine(); + if(word.equals("stop")) { + this.downService(); // харакири + break; // если пришла пустая строка - выходим из цикла прослушки + } + System.out.println("Echoing: " + word); + Server.story.addStoryEl(word); + for (ServerSomthing vr : Server.serverList) { + vr.send(word); // отослать принятое сообщение с привязанного клиента всем остальным влючая его + } + } + } catch (NullPointerException ignored) {} + + + } catch (IOException e) { + this.downService(); + } + } + + /** + * отсылка одного сообщения клиенту по указанному потоку + * @param msg + */ + private void send(String msg) { + try { + out.write(msg + "\n"); + out.flush(); + } catch (IOException ignored) {} + + } + + /** + * закрытие сервера + * прерывание себя как нити и удаление из списка нитей + */ + private void downService() { + try { + if(!socket.isClosed()) { + socket.close(); + in.close(); + out.close(); + for (ServerSomthing vr : Server.serverList) { + if(vr.equals(this)) vr.interrupt(); + Server.serverList.remove(this); + } + } + } catch (IOException ignored) {} + } +} + +/** + * класс хранящий в ссылочном приватном + * списке информацию о последних 10 (или меньше) сообщениях + */ + +class Story { + + private LinkedList story = new LinkedList<>(); + + /** + * добавить новый элемент в список + * @param el + */ + + public void addStoryEl(String el) { + // если сообщений больше 10, удаляем первое и добавляем новое + // иначе просто добавить + if (story.size() >= 10) { + story.removeFirst(); + story.add(el); + } else { + story.add(el); + } + } + + /** + * отсылаем последовательно каждое сообщение из списка + * в поток вывода данному клиенту (новому подключению) + * @param writer + */ + + public void printStory(BufferedWriter writer) { + if(story.size() > 0) { + try { + writer.write("History messages" + "\n"); + for (String vr : story) { + writer.write(vr + "\n"); + } + writer.write("/...." + "\n"); + writer.flush(); + } catch (IOException ignored) {} + + } + + } +} + +public class Server { + + public static final int PORT = 8080; + public static LinkedList serverList = new LinkedList<>(); // список всех нитей - экземпляров + // сервера, слушающих каждый своего клиента + public static Story story; // история переписки + + /** + * @param args + * @throws IOException + */ + + public static void main(String[] args) throws IOException { + ServerSocket server = new ServerSocket(PORT); + story = new Story(); + System.out.println("Server Started"); + try { + while (true) { + // Блокируется до возникновения нового соединения: + Socket socket = server.accept(); + try { + serverList.add(new ServerSomthing(socket)); // добавить новое соединенние в список + } catch (IOException e) { + // Если завершится неудачей, закрывается сокет, + // в противном случае, нить закроет его: + socket.close(); + } + } + } finally { + server.close(); + } + } +} \ No newline at end of file diff --git a/src/test/java/ru/molokoin/AppTest.java b/src/test/java/ru/molokoin/AppTest.java new file mode 100644 index 0000000..fbee865 --- /dev/null +++ b/src/test/java/ru/molokoin/AppTest.java @@ -0,0 +1,20 @@ +package ru.molokoin; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +}