esoe
2 years ago
commit
7a137e2797
3 changed files with 272 additions and 0 deletions
@ -0,0 +1,75 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>ru.molokoin</groupId> |
||||||
|
<artifactId>chat-server</artifactId> |
||||||
|
<version>0.1</version> |
||||||
|
|
||||||
|
<name>chat-server</name> |
||||||
|
<!-- FIXME change it to the project's website --> |
||||||
|
<url>http://www.example.com</url> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||||
|
<maven.compiler.source>1.7</maven.compiler.source> |
||||||
|
<maven.compiler.target>1.7</maven.compiler.target> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<version>4.11</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> |
||||||
|
<plugins> |
||||||
|
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-clean-plugin</artifactId> |
||||||
|
<version>3.1.0</version> |
||||||
|
</plugin> |
||||||
|
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-resources-plugin</artifactId> |
||||||
|
<version>3.0.2</version> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||||
|
<version>3.8.0</version> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-surefire-plugin</artifactId> |
||||||
|
<version>2.22.1</version> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-jar-plugin</artifactId> |
||||||
|
<version>3.0.2</version> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-install-plugin</artifactId> |
||||||
|
<version>2.5.2</version> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-deploy-plugin</artifactId> |
||||||
|
<version>2.8.2</version> |
||||||
|
</plugin> |
||||||
|
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-site-plugin</artifactId> |
||||||
|
<version>3.7.1</version> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-project-info-reports-plugin</artifactId> |
||||||
|
<version>3.0.0</version> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</pluginManagement> |
||||||
|
</build> |
||||||
|
</project> |
@ -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<String> 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<ServerSomthing> 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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 ); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue