Синхронизация сервера и клиента по протоколу TCP
Имеется сервер, организованный с помощью TcpListener, и клиент, организованный с помощью TcpClient. Данных от клиента серверу пересылается много, поэтому делается это построчно. Дело в том, что при пересылке сообщения от клиента к серверу последнему нужно некоторое время для обработки данных (вставляет данные из полученного сообщения в БД). Если поставить какой-нибудь примитивный Thread.Sleep(1000) перед каждым отправлением данных, то тогда сервер успевает за клиентом, но этот метод мне крайне не нравится. Как заставить их синхронизироваться друг с другом?
Ответы (1 шт):
Автор решения: Blackmeser
→ Ссылка
- Клиент посылает серверу пакет с сообщением. (используйте преимущественно json)
- Сервер в
lock()добавляет добавляет сообщение вConcurrentDictionary<long, string>, но проверяяlongна уникальность дляDictionary,longберётся на основеDateTime.Now.Ticksна стороне сервера, еслиlongне уникален - делаетсяlong++пока не станет уникальным. - Сервер сразу отвечает клиенту что
longпринят и встал в очередь на обработку. - Клиент принимает
longи заводит его вList<long>ожидающий подтверждения записи на стороне сервера. - Клиент в цикле по таймеру запрашивает у сервера
List<long>ожидающих подтверждения записи. - Сервер так-же крутит в цикле свой
ConcurrentDictionary<long, string>и еслиDictionaryне пустой - берёт сообщения и отправляет на запись в БД. Записанные сообщения удаляет изDictionary. - Сервер при получении
List<long>(пусть будет буфером) сверяет его сConcurrentDictionary<long, string>внутриlock()и если вDictionaryнетlong- удаляет его изList<long>буфера. - Сервер отвечает отфильтрованным
List<long>, в котором будут содержаться только теlong, которые ещё не были записаны в БД. - Клиент сравнивает исходный отправленный
List<long>(не текущий, т.к. могли появиться ещё сообщения) и полученныйList<long>от сервера (вниманиеList<long>должен быть пустой, а не null), после чего клиент удаляет записанные в БДlongидентификаторы сообщений из текущегоList<long>.
Это пример примитивной клиент-серверной архитектуры.
Достоинства:
- Придумана за 15 минут
- Примитивный
- Можно развивать!!! (в любом направлении)
- Можно очень просто сделать разные типы сообщений, не только текстовая строка
- Никто никого не ждёт (клиент не ждёт пока сервер запишет сообщение в БД)
- Есть система подтверждений о записи в БД (синхронизация, условно можно рисовать галочки как в Телеграм)
- Можно изменять принципы синхронизации как душе угодно, например выбросить
List<long>и сделать что-то более надёжное и осмысленное, и так-же заменитьDictionary<long, string>на какой-нибудь более полноценныйDictionary<id_struct, ICustomMessage> - Быстрая синхронизация, запрашивать можно хоть каждую 1/100 секунды, если ожидающих запись в БД сообщений не очень много
- Поддержка многопоточности на уровне концепта (вся работа с сервером может быть в отдельном потоке или по таймерам, ничего не сломается, но не нужно забывать что интерфейс клиента всегда должен обновляться через Invoke(), если у вас GUI на формах)
Недостатки:
- Придумана за 15 минут
- Забагованный (по любому есть косяки, например клиент пометит что сообщение записано в БД если сервер перезагрузится, это нужно лучше продумывать и вместо
List<long>использовать какой-нибудь более надёжный подход) - Требует продуманной системы сообщений (построчно писать не получится, хотя тем-же json'ом можно и в одну строку, но лучше так не делать)