Skip to content

Latest commit

 

History

History
236 lines (147 loc) · 14.7 KB

Messenger.md

File metadata and controls

236 lines (147 loc) · 14.7 KB

Проект Мессенджер

Описание Разработка сервера для мессенджера - системы обмена сообщениями.

Техническое задание

Версия 29.03.2016

Команды

  • мессенджер поддерживает обработку команд от пользователя в специальном формате, начинающемся с /
  • в случае ошибки выполнения команды, сервер возвращает статус ошибки (неправильные аргументы, не залогинен и т д)

Ниже описан консольный интерфейс команд. При передаче по сети их можно кодировать с помощью enum, например

// Список кодов сообщений
public enum MessageType {
  USER_LOGIN, // команда /login
  USER_INFO,  // команда /user_info
  MSG_SEND, // и тд 
  CHAT_LIST,
  CHAT_SEND,
}

// Примерный код класса сообщения
class LoginMessage {
  MessageType type;
  String login;
  String pass;
}  

Help

/help

показать список команд и общий хэлп по месседжеру

UserInfo

/login <логин_пользователя> <пароль>

/login arhangeldim qwerty

залогиниться (если логин не указан, то авторизоваться). В случае успеха приходит вся инфа о пользователе

/user <никнейм>

добавить никнейм для текущего пользователя (только для залогиненных пользователей)

/user_info [id]

/user_info инфа о себе

/user_info 3 - инфа о пользователе 3

получить всю информацию о пользователе, без аргументов - о себе (только для залогиненных пользователей)

/user_pass <old_pass> <new_pass>

/user_pass qwerty 123qaz

сменить пароль (только для залогиненных пользователей)

Chat

/chat_list

получить список чатов пользователя(только для залогиненных пользователей). От сервера приходит список id чатов

/chat_create <user_id list>

/chat_create 1,2,3,4 - создать чат с пользователями id=1, id=2, id=3, id=4

/chat_create 3 - создать чат с пользователем id=3, если такой чат уже существует, вернуть существующий

создать новый чат, список пользователей приглашенных в чат (только для залогиненных пользователей).

/chat_history <chat_id>

/chat_history 2 - сообщения из чата id=2

список сообщений из указанного чата (только для залогиненных пользователей)

/chat_find <chat_id> <regex>

/chat_find 3 pizza - найти все вхождения слова pizza в чате id=3, сервер вернет все сообщения с этим словом

поиск в чате подстроки, соответсвующей регулярному выражению (только для залогиненных пользователей)

/chat_send <id> <message>

/chat_send 3 Hello, it's pizza time! - отправить указанное сообщение в чат id=3

отправить сообщение в заданный чат, чат должен быть в списке чатов пользователя (только для залогиненных пользователей)

Таким образом любое сообщение, которое проходит между сервисом-клиентом - это некая команда.

  • чтобы начать пользоваться мессенджером, пользователь должен предварительно авторизоваться (логин/пароль);
  • пользователя можно найти по логину;
  • пользователь может отправить сообщение другому пользователю;
  • история сообщений сохраняется;
  • пользователь может посмотреть историю своих разговоров;
  • мессенджер поддерживает обработку команд от пользователя в специальном формате (например, /help);
  • пользователи, история (чаты) - хранятся в базе данных
  • мессенджер работает через сетевое соединение
  • для взаимодействия клиент-сервер необходимо разработать протокол

Протокол

Чтобы передавать по сети сложные данные (объекты, коллекции) нужно разработать протокол общения. Протокол может быть текстовым или бинарным. Текстовый протокол проще для отладки, также можно использовать формат json для представления объекта в виде строки. Итоговая строка конвертируется в byte[] - байтовый массив и отправляется в сокет. Бинарый протокол лучше, с точки зрения производительности и трафика, но сложнее в отладке. можно разработать свой протокол, можно воспользоваться встроенным механизмом сериализации

Рекомендую использовать сериализацию, также возможно использования json библиотеки - например Jackson

JSON http://www.mkyong.com/java/jackson-2-convert-java-object-to-from-json/ (ссылка в репозиторий maven и примеры там есть)

Serializable http://skipy.ru/technics/serialization.html http://www.ccfit.nsu.ru/~deviv/courses/oop/java_ser_rus.html

Интерфейс протокол описан в ru.mail.track.message.Protocol Умеет преобразовывать набор байт в сообщение и наоборот

Ваша реализация должна от него наследоваться

Архитектура сервиса

На стороне сервера можно выделить следующие сущности -

  • User(пользователь)
  • Message(Сообщение)
  • Chat(Разговор, чат)

У каждой сущности есть уникальный идентификатор (Long id). Данные на сервере хранятся в хранилище (базе данных), за взаимодействие с бд отвечают интерфейсы UserStore (пользователи) и MessageStore (сообщения и чаты). С помощью этих интерфейсов можно получить сущности.

Примерная диаграмма классов

alt tag

Примерная схема потока данных (данные идут как по стрелкам клиент-сервер, так и в обратную сторону)

alt tag

Описание

Общение пользователей происходит в чатах. Чат - это разговор 2х и более пользователей. Каждый пользователь может создавать чат. Чат создается командой /chat <ids>, где <ids> - это список участников чата. При попытке создать диалог (2 участника), возвращается существующий чат (как личные сообщения в соц сетях). При создании мультичата (> 2 участников) - создается новый, даже если существует чат с таким же набором участников.

Клиент может получить список чатов, в которых он принимал участие и просмотреть историю переписки (все данные запрашиваются с сервера)

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

На стороне сервера можно выделить следующие сущности - User(пользователь), Message(Сообщение), Chat(Разговор, чат). У каждой сущности есть уникальный идентификатор (Long id). Данные на сервере хранятся в хранилище (базе данных), за взаимодействие с бд отвечают интерфейсы UserStore (пользователи) и MessageStore (сообщения и чаты). С помощью этих интерфейсов можно получить сущности.

Общение с сервером происходит через сокеты, сервер умеет обрабатывать запросы от клиентов в несколько потоков. Когда кто-то присылает сообщение в чат, остальные участники чата получают это сообщение. С каждым клиентом связан поток-обаботчик на стороне сервиса, который держит соединение. Засчет этого обеспечивается постоянная двусторонняя связь.

Summary

Код должен состоять из независимых модулей, общающихся друг с другом через интерфейсы. Модуль должен быть вынесен в отдельный package. Не забывайте, что при хорошем ООП дизайне, каждый класс должен решать определенную задачу и, желательно, только её. Также большое внимание уделите оформлению кода и его чистоте: Code Style Guide Полный гайд от гугла на англ. Некоторые рекоммендации на рус.

В коде нужно правильно обрабатывать исключительные ситуации и уметь объяснить, почему обработка происходит таким образом. Чтобы определиться с исключениями, подумайте какую задачу вы решаете и как должна себя вести система в том или ином случае. Исключение - это обработка именно нештатных ситуаций, неожидаемое поведение.

Для обработки и хранения данных правильно используйте коллекции. Нужно уметь объяснить свой выбор той или иной структуры данных, знать основные свойства (контракт, скорость доступа, добавление, удаление элементов).

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

Большое внимание уделите работе с потоками и корректной их остановке.

Итого,

  • архитектура приложения (разделение на модули и классы, распределение ответсвенности между ними)
  • использование интерфейсов и наследования
  • ошибки разработчика (незакрытые ресурсы, необработанные исключения, неправильная проверка условий)
  • выбор способа хранения данных (правильно ли выбран коллекция для задачи, правильно ли выбран алгоритм, структура таблиц базы данных)
  • читаемость кода и его оформление
  • Нужно поработать над протоколом - механизмом преобразования объектов в byte[] и обратно. Это может быть сделано с помощью сериализации.

http://habrahabr.ru/post/60317/ http://skipy.ru/technics/serialization.html http://www.codeproject.com/Tips/991180/Java-Sockets-and-Serialization

Сериализация через сокет выглядит очень просто, достаточно обернуть stream

socket = new Socket(InetAddress.getLocalHost(), portNumber);

// Обернем стримы и получим стримы для чтения и записи объектов
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket1.getOutputStream());

Message msg = new LoginMessage();

// На одной стороне пишем
oos.writeObject(msg);
oos.flush();


// С другой стороны читаем
// Класс Message должен implements Serializable
Message msg = (Message) ois.readObject();
  • По сети должны передаваться объекты-сообщения.
  • Поддерживается команда получения на клиенте полной истории разговора по chatId