Всем привет!
Решил я значит на java сотворить свой десктопный мессенджер по типу тележки и... (о как удивительно) столкнулся с некоторыми архитектурными вопросами, которые я просто не могу решить. Очень надеюсь, что здесь мне смогут дать совет или помочь.
В общем, предполагается, что обмен сообщений между клиентами будет происходить через сокеты. Если конкретно, то у нас есть сущность - комната чата, к каждому чату присвоен свой Server Socket, к которому подключено определённое число соединений(клиентов). Управление этими сервер сокетами(создание, удаление, хранение) происходит удалённо, скажем, в другой программе с которой связывается клиент через всё те же сокеты(только при необходимости).
У этого подхода есть определённые плюсы, например, в случае ошибки в одном чате, у нас не ляжет весь мессенджер. Так же можно выделить высокую скорость отправки сообщений, ибо они не проходят через какой либо парсинг или что-то в этом духе, за исключением разве что определённой визуализации на javaFX. Хоть я вроде настроил систему динамического обновления портов для каждого чата(то есть, если чат не активен, его порт освобождается), всё равно остаётся риск, что при высоких нагрузках, порты на стороне сервера могут тупо закончится. У меня даже не остаётся идей как это исправлять. Может нужно менять подход? Если да, то на какой?
Я только учусь и это мой первый крупный проект, поэтому не судите строго
В общем, предполагается, что обмен сообщений между клиентами будет происходить через сокеты.
Когда вы делаете соединение между двумя нодами, то проблем нет как передавать сообщения. А когда появляется сущность "комната чата" или "беседка", то появляется вопрос, кто должен синхронизировать состояние комнаты, и какая нода будет главной. Если у вас централизованный способ взаимодействия, то у вас в архитектуре должна быть особая нода - серверная часть приложения, которая хранит в своей базе данных (или в оперативной памяти воспроизводит актуальное состояние) состояние комнаты, производит авторизацию пользователя, проверяет целостность доставки сообщения, обеспечивает передачу состояния всем своим пользователям клиентам. А все ноды-клиенты подключаются к серверу, забирают из него состояние комнаты, отправляют свои изменения (сервер принимает изменения, если они не противоречат разрешенным переходам в другое состояние). Каждый клиент хранит у себя только часть состояния комнат в своей локальной памяти, или локальной базе данных, изменения фиксируются только после того, как они отправлены на сервер и верифицированы сервером как допустимое изменение.
Если у вас одноранговая структура обмена сообщений, то сервер вам нужен лишь для создания среды обмена - в простейшем случае в качестве такой среды может выступать локальная сеть, если нужна более сложная структура, то уже одним протоколами TCP/UDP и сетевым роутером не обойдешься, нужен протокол, который вам обеспечит виртуальную локальную сеть, или как-то сделает общую шину для обмена сообщениями. В такой структуре каждый клиент будет содержать полную копию состояния комнаты и обновлять его используя данные общей шины.
У этого подхода есть определённые плюсы, например, в случае ошибки в одном чате, у нас не ляжет весь мессенджер.
Во-первых, у вас они не в одной ноде выполняться будут, а на разных.
Во-вторых, если вы в коде правильно обернете в исключения процесс отправки сообщений, приема, сериализации/дисериализации, то в случае появления исключения вы зададите альтернативный метод обработки каждого нештатного состояния. Если у вас будет наибольший охват всех нештатных ситуаций, то вероятность падения конкретной ноды будет минимальной.
скорость отправки сообщений, ибо они не проходят через какой либо парсинг или что-то в этом духе, за исключением разве что определённой визуализации на javaFX.
Вся сложность не в скорости отправки и получения сообщений, а контроле целостности состояния и синхронизации его.
всё равно остаётся риск, что при высоких нагрузках, порты на стороне сервера могут тупо закончится.
Пока вы крутитесь на локалхосте, то у вас 65 тыс. портов, но в реальной жизни, на одном IP адресе не так уж много клиентов сидит, поэтому умножайте на кол-во разнородных IP ваших клиентов.
Я только учусь и это мой первый крупный проект, поэтому не судите строго
Ну, на первый раз побаловаться пойдет. Поймете все сложности создания клиент-серверного приложения, особенно, когда клиентов больше двух и нужно обеспечивать синхронизацию действий.
Причем, сложность вашей задачки такая же как создать игровой сервер для той же CS.
Управление этими сервер сокетами(создание, удаление, хранение) происходит удалённо .... остаётся риск, что при высоких нагрузках, порты на стороне сервера могут тупо закончится.
Если вы не планируете видео-трансляции в своём мессенджере, возможно имеет смысл использовать UDP протокол. То есть, отправил сообщение и сразу закрыл/освободил порт. А для звонков и видео использовать TCP. Так вы сможете экономить ресурсы.
Безусловно, всё это зависит от того, какие задачи должно решать ваше приложение: передача текстовых сообщений, файлов, видео, звонки. Всё это влияет на архитектуру приложения, его скорость и качество.
Лично я когда-то писал поискового робота (примитивный аналог Google, Yandex и др.) и могу сказать, что ограничение TCP/IP в ~65 тысяч клиентских соединений тесно связано с оборудованием и операционной системой. Это актуально в том случае, если вы создаёте каждый раз новый канал (например, если вы подключаетесь каждую секунду к 100 разным сайтам). В вашем случае, это должны быть комнаты чата. И если всё правильно написано, то достигнуть лимита даже в 65К будет сложно.
Если конкретно, то у нас есть сущность - комната чата, к каждому чату присвоен свой Server Socket, к которому подключено определённое число соединений(клиентов).
Вам не нужен сокет на каждого клиента, если он в данный момент времени не активен. Основная нагрузка - (видео) звонки и передача файлов. А текстовые сообщения - это одноразовые события. Для них не нужно создавать постоянное TCP/IP соединение.