DMconnect - протокол внутренней работы.

Принцип работы сервера изнутри.

 

В прошлых документациях мы уже подробно рассмотрели то, каким именно образом нужно строить свой клиент, и как обрабатывать ответы от сервера, попутно дав приблизительную логику вывода этих ответов. На данный момент (1 марта 2025), к сожалению, исходный код сервера новых версий протокола (v2 и v3) недоступен, поэтому мы будем основываться на принципе работы v1-сервера, исходный код которого, в свою очередь, уже открыт.

Подключение - обработка
Благодаря ngc7000, мы получили пакеты, отправляемые сервером клиенту во время подключения, в сыром виде, вот они:



--- Новый пакет ---
[2025-01-24 19:31:04.171015] Пакет: 56 Bytes
IP Источник: 127.0.0.1 | IP Назначение: 127.0.0.1
Порты: 56503 -> 1111
0000 02 00 00 00 45 00 00 34 22 7E 40 00 80 06 00 00 ....E..4"~@.....
0010 7F 00 00 01 7F 00 00 01 DC B7 04 57 02 E8 79 EA ...........W..y.
0020 00 00 00 00 80 02 FF FF 19 09 00 00 02 04 FF D7 ................
0030 01 03 03 08 01 01 04 02 ........

--- Новый пакет ---
[2025-01-24 19:31:04.173022] Пакет: 56 Bytes
IP Источник: 127.0.0.1 | IP Назначение: 127.0.0.1
Порты: 1111 -> 56503
0000 02 00 00 00 45 00 00 34 22 7F 40 00 80 06 00 00 ....E..4".@.....
0010 7F 00 00 01 7F 00 00 01 04 57 DC B7 46 AD 4D 6E .........W..F.Mn
0020 02 E8 79 EB 80 12 FF FF 84 DC 00 00 02 04 FF D7 ..y.............
0030 01 03 03 08 01 01 04 02 ........

--- Новый пакет ---
[2025-01-24 19:31:04.175021] Пакет: 44 Bytes
IP Источник: 127.0.0.1 | IP Назначение: 127.0.0.1
Порты: 56503 -> 1111
0000 02 00 00 00 45 00 00 28 22 80 40 00 80 06 00 00 ....E..(".@.....
0010 7F 00 00 01 7F 00 00 01 DC B7 04 57 02 E8 79 EB ...........W..y.
0020 46 AD 4D 6F 50 10 04 FF BA D4 00 00 F.MoP.......

--- Новый пакет ---
[2025-01-24 19:31:04.176027] Пакет: 78 Bytes
IP Источник: 127.0.0.1 | IP Назначение: 127.0.0.1
Порты: 1111 -> 56503
0000 02 00 00 00 45 00 00 4A 22 81 40 00 80 06 00 00 ....E..J".@.....
0010 7F 00 00 01 7F 00 00 01 04 57 DC B7 46 AD 4D 6F .........W..F.Mo
0020 02 E8 79 EB 50 18 20 FA 53 2B 00 00 45 6E 74 65 ..y.P. .S+..Ente
0030 72 20 63 6F 6D 6D 61 6E 64 20 28 2F 6C 6F 67 69 r command (/logi
0040 6E 20 2F 72 65 67 69 73 74 65 72 29 3A 20 n /register): 

--- Новый пакет ---
[2025-01-24 19:31:04.177022] Пакет: 44 Bytes
IP Источник: 127.0.0.1 | IP Назначение: 127.0.0.1
Порты: 56503 -> 1111
0000 02 00 00 00 45 00 00 28 22 82 40 00 80 06 00 00 ....E..(".@.....
0010 7F 00 00 01 7F 00 00 01 DC B7 04 57 02 E8 79 EB ...........W..y.
0020 46 AD 4D 91 50 10 04 FF BA B2 00 00 F.M.P.......

--- Новый пакет ---
[2025-01-24 19:31:17.922860] Пакет: 44 Bytes
IP Источник: 127.0.0.1 | IP Назначение: 127.0.0.1
Порты: 56503 -> 1111
0000 02 00 00 00 45 00 00 28 22 CB 40 00 80 06 00 00 ....E..(".@.....
0010 7F 00 00 01 7F 00 00 01 DC B7 04 57 02 E8 79 EB ...........W..y.
0020 46 AD 4D 91 50 14 00 00 BF AD 00 00 F.M.P.......

То, что происходит, думаю, будет понятно большинству (не сарказм ;-)). Сначала, проходит трехстороннее TCP-рукопожатие (на него, в целом, можете не обращать никакого внмиания - оно нам не пригодится). 4 пакет - обозначение о начале обмена данными (Enter command /login /register), четвертый - продолжение приёма.
Отметим, все пакеты начинаются с 0000 02, любой другой пакет приведет к отключению клиента (об этом позже), а самому клиенту от принятия таких "полупакетов" сделается ой как плохо. Вот, в общем-то и все с подключением, можем переходить далее...

Отключение приёма сообщений от клиента
Эту тему еще никто не обговаривал, но это факт. Взглянем на основной код приёма сообщений клиента по TCP в v1-протоколе (в v3 #4 используется тот же принцип, да и вообще во всех версиях он един):

message = client_socket.recv(1024).decode('utf-8').strip()

if not message:
    break

Это находится в самом начале цикла приёма, то есть, независимо от того, авторизован ли пользователь или нет. Фактически, это автоматически отключает клиента, в случае, если сообщение нельзя сократить (сделать .strip()), например строку "    test" превратить в " test", как это делают многие программы, совсем не имеющие отношения к DMconnect. Сокращает сервер тут только сам текстовый (Plain-text) пакета, а не его байты (см. выше, дамп трафика). Проведите эксперимент, подключитесь к серверу (например, по инструкции dmconnectcc, но уберите из кода строки, как раз сокращающие (.strip()) сообщения на стороне клиента, дабы ни в коем случае не отправить на сервер "неправильное" сообщение), а потом отправьте одно простое сообщение - " " (пробел). Вы, возможно, даже ничего не увидите (ошибок об отключении, принудительный разрыв связи и т. д.), но, тем не менее, будете отключены. Как показывает практика, при отключении (останове приема связи) тоже отправляется пакет, который сервер не может расшифровать, таким образом, клиент отключается. Зачем так сделано - одному Богу (или разработчикам DMconnect :D) известно, но факт остаётся фактом, и с этим придётся мириться.

Обработка личных сообщений
Поскольку система ЛС (личных, приватных сообщений) появилась только в версии протокола v2 #0, приходится все же использовать свою фантазию :-)) Однако, на каком-то форуме (уже никому не известно, на каком именно, но точно на каком-то) при обсуждении систем работы DMconnect, оператор предоставил выдержку из серверной части, показывающей принцип работы PM-системы (ЛС-системы):

async def send_private_message(sender, recipient, message):
recipient_ws = active_users.get(recipient)

if isinstance(recipient_ws, websockets.WebSocketServerProtocol):
    try:
        await recipient_ws.send(f"(Private) {sender}: {message}")
        return True
    except Exception as e:
        log_message(f"Error sending private message to WebSocket client: {e}")
        return False

elif isinstance(recipient_ws, socket.socket):
    try:
        recipient_ws.send(f"(Private) {sender}: {message}\n".encode('utf-8'))
        return True
    except Exception as e:
        log_message(f"Error sending private message to TCP client: {e}")
        return False

return False

Все по стандарту - обычная кодировка UTF-8. Нелегкими тестами на основе серв. части v1, удалось выяснить, что:

active_users - это, в свою очередь, массив, куда добавляются объекты сокетов подключенных клиентов, а при выборе принципа отправки (если вы не поняли) код выбираются либо WSSP, либо S.S (TCP).