Public Text Chat Server

image
Данная статья будет интересна людям, интересующимся сетями, логическим устройством серверов и нативным программированием. Здесь не будет долгих листингов исходных кодов, а только общие наброски и подходы.
TL; DR GitHubЭто как имиджборж только текстовый
Такой же текстовый, как и по большей мере этот пост.
Возвращаясь к своей детской мечте, мне захотелось сделать текстовый чат. Для меня это как один из вариантов увеличить количество недостающих api в библиотеке, т.к. только таким путем понимаешь по настоящему, что необходимо программисту, когда пишешь что-то более менее прикладное.

Постановка проблемы


  • Реализовать TCP-multithread текстовый чат-сервер, к которому можно коннектиться и получать рассылку сообщений, а так же отправлять свои. В качестве клиента должно быть невероятно простое ПО — например nc. Или любой TCP-сокет, который принимает и отправляет данные (keep-alive, как привыкли web-программисты,.т.е поддерживает соединение).
  • Сегментация трафика по средствам стандартных чатрумов (меняем чатрум больше не получаем данные пользователей в старом чатруме).
  • Т.к. есть чатрумы — возможность просмотра людей в чатруме.
  • Привязка ника к определенной паре ip: port, при этом возможность его менять.
  • Ну и такая же маленькая текстовая админка (выкл сервера, получения статы и подобное)

Теоритическая часть


В сокетах беркли, которые работают с TCP протоколом есть API connect/accept, чтобы выполнить трехстороннее рукопожатие, и потом в скрытом от программиста режиме организовать поток, с контролем доставки и целостности данных. Проблема в том, что conntect/accept это блокирующий вызов, и нельзя подключится к нескольким портам одновременно (одним сокетом), чтобы этого не делать и снизить нагрузку на вычислительное устройство (поддержание большого количества коннектов) придумали клиент-серверную архитектуру, в которой сервер будет агрегировать весь трафик присылаемый на него разными клиентами и поддерживать те самые множественные соединения.
Есть два решения проблемы поддержания множественных connect/accept для серверов — это мультипоточность и использование неблокирующих сокетов. Я буду рассматривать первый случай, потому что это мне ближе.

Проектирование

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

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

Как я делал это
Для того, чтобы написать TCPConnectionHandler, сначала необходимо написать ThreadPool, который бы имел возможность создания и прерывания потоков (и разделение потоков на тех, которые находятся в состоянии завершения, и тех, которые находятся в работе).
А TCPConnectionHandler смотрел бы какие из соединений завершились, отвечал за broadcast/multicast рассылки к подключенным сокетам, и хранение/уничтожение пользовательских данных, которыми обладает сокет.

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

Микро-Админка


Администрирование серверов, которые поддерживают только открытый коннект (без шифрования) вообще должно заслуживать отдельной статьи о том, как можно построить стойкую систему одноразовых паролей и хеш-комманд, но опустим все это. Я просто использовал возможность ввода текстового ключа, и команды за ним, для выполнения (Если длинна ключа будет достаточно велика несколько мегабайт, то можно обезопасить себя от брутфорса), но тяжело обезопасить себя от перехвата этого самого ключа=). Но, теоритически, схема выглядит так:

  1. Сервер генерирует challenge число или набор байт.
  2. Клиент хеширует одноразовым ключем challenge + комманду и отравляет хеш и комманду в открытом виде.
  3. Сервер повторно хеширует команду с challenge и сравнивает результат хеша с полученным.
  4. Если хеш валидный то комманда выполняется.

Примеры команд


Окно приветствия с маленьким help.
33f1e9ae5bb34b388963fcba959aec15.png

Скрытые возможности текстового чата


1. Обмен данными по хеш-чатрумам
Например не один нормальный пользователь не будет сидеть в чатруме с названием PbgkkCzrM8VToEgcDcCSfQdw5p1IaoRHiBu5d21XGv92c0fKmJUo3XoxFqtdN5tOzmRY5PrSQti6uKFOZTatQQ==
А вот боты вполне. И менять эти комнаты спустя некоторое время.2. Прозрачное шифрование в текстовом представлении Base64.
Мы все уже привыкли к автоматическому шифрованию данных, а как будет ностальгично слать данные собеседникам, которые были зашифрованы с pre-shared-key.3. Анонимность, привязанная только к паре ip: port (привет tor, i2p), и идентификация/аутентификация с собеседниками в пределах поддерживаемой сессии. 4. Легковесность данных.
Никакого дополнительного payload для поддержки сессии, или передачи контента. Только текстовый контент.5. Простой клиент (nc, putty, etc) 6. Легковесность и производительность сервера
На моем маке используемая библиотека и клиент скомпилированные без оптимизаций весят 156 + 40 = 196 Кб. Т.е. возможность запускать на старых устройствах, с малым количеством оперативной памяти, и минимальной поддержкой POSIX.7. OpenSource — открытость, и ничего лишнего. + возможность внести свои собственные доработки, как шифрование, идентификацию,
аутентификацию, передачу файлов и т.д.

GitHub, но держите сильно-впечатлительных подальше от монитора.
CMake, позволяет собрать под свою платформу и запустить на локальном хосте, mac/linux (+ windows in future с вашей помощью).
Допиливание фич по требованию.
a61cee5a3232417c8ca198a289c5451b.png

© Habrahabr.ru