Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.84/19: Рейтинг темы: голосов - 19, средняя оценка - 4.84
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
1

Ваша реализация получения сообщений по определенному протоколу

06.10.2012, 17:04. Показов 3379. Ответов 53
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Третьего дня получил задание - реализовать клиентскую часть одного сетевого протокольчика.
Протокол простенький по своей спецификации, я бы даже сказал примитивный, но пара моментов реализации вкупе с несколькими условиями, которые были поставлены, создали довольно интересную задачку.
Настолько интересную, что захотелось поделиться ей с общественностью.

Спецификация:
1. Общение клиента с сервером происходит по протоколу TCP.
2. Общение инициирует клиент, первым отсылая сообщение.
3. Протокол асинхронный, то есть сервер может как отвечать на клиентские запросы, так и слать сообщения без предупреждения (уведомления о всяких событиях). Через это клиент должен постоянно находиться в режиме приема сообщений.
4. Сообщение - это строка незашифрованного текста в кодировке UTF-8.
5. Сообщения разделяются символом \n
6. Символ \r игнорируется.
7. Сообщения состоят из параметров, разделенных пробелами.
8. Количество параметров неограничено, но их всегда как минимум два.
9. Длина каждого параметра неограничена*. Так же параметр может быть пустой строкой (два подряд идущих пробела, например).
10. Параметр может состоять из любых символов, имеющихся в таблице юникода.
11. Если в тексте параметра встречается конструкция вида {n}, где n - целое число в промежутке [0; int.MaxValue], то следующие n байтов текста после закрывающей квадратной скобки считываются как есть и являются частью этого параметра, то есть любые специальные символы не интерпретируются (напр. пробелы и переносы строки).

* Основная масса сообщений - довольно короткие, в районе 100 символов. Но, отослав определенный запрос, можно получить и портянку текста длиной в несколько мегабайт.

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

Ну и, конечно же, чтобы жизнь медом не казалась, имеется несколько обязательных к выполнению условий:
1. Максимально возможная эффективность обработки сообщений, т.к. обработчиков будет создано много (может быть в районе тысячи).
2. Вследствие первого пункта у обработчика должен быть минимальный футпринт в памяти, то есть в ходе работы объекты в куче стоит плодить только при крайней необходимости. К примеру, вполне разумно один раз создать буфер для приема данных, но весьма неразумно - создавать отдельный буфер для каждого сообщения. Если, конечно, ваше решение вообще будет использовать буферы (моё использует).
Обработчик будет частью другой, довольно сложной системы, потому должен быть максимально легковесным.
3. Вследствие все того же первого пункта обязательно использование асинхронной модели для приема сообщений, т.к. тысячу потоков вам никто не предоставит.

Вроде бы ничего не забыл.
Если кому-то нечего делать - попытайтесь реализовать.
Решение выкладывать не обязательно - это не просьба о помощи (решение уже есть).
Но очень интересно было бы услышать, с какой стороны вы бы подошли к проблеме.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.10.2012, 17:04
Ответы с готовыми решениями:

Необходимо разработать программу для получения почтовых сообщений по протоколу POP3
Здравствуйте. Помогите, пожалуйста, реализовать. Спасибо. Необходимо разработать программу для...

Соединение по определенному протоколу
есть сайт. chitamks.ru На нем пользователь через ЛК должен получить возможность узнать свою...

Передача сообщений по протоколу UDP
Всем привет, и с наступающим. Собственно есть необходимость передавать данные по udp протоколу,...

Настройка системы для отправки сообщений по протоколу SMTP
Всем привет, форумчанин! Задание на лабор. работу написано, что нужно вставить функцию mail() перед...

53
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
05.09.2017, 19:27 41
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от kolorotur Посмотреть сообщение
небольшой участок в стеке через stackalloc
А какого примерно размера?

Цитата Сообщение от kolorotur Посмотреть сообщение
готовое поле помещалось в List<string> пока не соберется полное сообщение
То есть это вариант с list.Add()?

Цитата Сообщение от kolorotur Посмотреть сообщение
список очищался и использовался заново для полей следующего сообщения
Переиспользование списка?

Хм... Очень интересно. Вы рассказали о своей реализации. И она совсем не такая, как у меня (то есть я бы делал по-другому).
0
192 / 199 / 82
Регистрация: 11.04.2013
Сообщений: 1,086
05.09.2017, 19:40 42
Цитата Сообщение от Fleder Посмотреть сообщение
готовое поле помещалось в List<string> пока не соберется полное сообщение
а зачем нужен List<string> если есть StringBuilder?

As others have pointed out, I would probably use StringBuilder. The List may have to resize many times; the new implementation of StringBuilder does not have to resize.
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
05.09.2017, 19:46 43
Цитата Сообщение от EVG-1980 Посмотреть сообщение
а зачем нужен List<string> если есть StringBuilder?
List<string> - полагаю, чтобы сформировать string[].
StringBuilder - чтобы сформировать строку.
0
192 / 199 / 82
Регистрация: 11.04.2013
Сообщений: 1,086
05.09.2017, 19:51 44
Цитата Сообщение от Fleder Посмотреть сообщение
List<string> - полагаю, чтобы сформировать string[].
Я к тому, если ввести какой нибудь служебный символ и просплитить не быстрее будет?

C#
1
2
3
StringBuilder sb = new StringBuilder();
sb.append("wd wdwq dwqd");
String[] myArray = sb.toString().split(" ");
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
05.09.2017, 19:59 45
Цитата Сообщение от EVG-1980 Посмотреть сообщение
Я к тому, если ввести какой нибудь служебный символ и просплитить не быстрее будет?
Конечно же это будет работать.
Тут дело в оптимальности и минимальном мемори футпринте.
0
192 / 199 / 82
Регистрация: 11.04.2013
Сообщений: 1,086
05.09.2017, 20:02 46
Цитата Сообщение от Fleder Посмотреть сообщение
Тут дело в оптимальности и минимальном мемори футпринте.
Я как раз на счет этого и спрашиваю
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
05.09.2017, 20:07 47
EVG-1980, этот код:
C#
1
2
3
StringBuilder sb = new StringBuilder();
sb.append("wd wdwq dwqd");
String[] myArray = sb.toString().split(" ");
Не самым оптимальным образом использует память.
0
192 / 199 / 82
Регистрация: 11.04.2013
Сообщений: 1,086
05.09.2017, 20:12 48
Цитата Сообщение от Fleder Посмотреть сообщение
Не самым оптимальным образом использует память.
Объясни почему List и StringBuilder будет эффективнее?
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
05.09.2017, 22:43  [ТС] 49
Цитата Сообщение от Fleder Посмотреть сообщение
А какого примерно размера?
256 символов, если память не изменяет.

Цитата Сообщение от Fleder Посмотреть сообщение
То есть это вариант с list.Add()?
Ага.

Цитата Сообщение от Fleder Посмотреть сообщение
Переиспользование списка?
Ага, после того как полное сообщение готово — вызов Clear.

Цитата Сообщение от EVG-1980 Посмотреть сообщение
а зачем нужен List<string> если есть StringBuilder?
В список складываются полностью считанные поля пока не будет готово полное сообщение.
В StringBuilder накапливается поле, которое считывается в данный момент.

Цитата Сообщение от EVG-1980 Посмотреть сообщение
если ввести какой нибудь служебный символ и просплитить не быстрее будет?
Нет, коробочный сплит не очень эффективный — у него сложность O(3n), если я не ошибаюсь. Плюс лишний мусор.

Цитата Сообщение от EVG-1980 Посмотреть сообщение
почему List и StringBuilder будет эффективнее?
Если уж сравнивать, то просто List, т.к. StringBuilder будет использоваться в обоих случаях и "выносится за скобки".
Список удобнее потому что не создает в памяти одну большую строку, которая все равно потом выбросится. Лишний мусор.
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
12.09.2017, 19:51 50
Цитата Сообщение от kolorotur Посмотреть сообщение
Ради интереса попробовал отправить сообщение вида {+n} и { n } — сервер понял.
Цитата Сообщение от kolorotur Посмотреть сообщение
Сервер 64-битный.
Подозреваю, что если скормить ему сообщение длиной больше, чем long.MaxValue, то он упадет, т.к. на предыдущее сообщение съел 2 гига оперативы.
Правильно ли я понял:
Вы отправили серверу сообщение с конструкцией {int.MaxValue} (но само это сообщение, естественно, не было такого размера),
сервер распарсил эту конструкцию и начал "стакать" все последующие сообщения от других клиентов, как одно гигантское поле?
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
12.09.2017, 22:06  [ТС] 51
Цитата Сообщение от Fleder Посмотреть сообщение
Вы отправили серверу сообщение с конструкцией {int.MaxValue}
Ага.

Цитата Сообщение от Fleder Посмотреть сообщение
но само это сообщение, естественно, не было такого размера
Нет, размер передаваемых данных соответствовал заявленному. То есть 2 гига по сети ушло.

Цитата Сообщение от Fleder Посмотреть сообщение
сервер распарсил эту конструкцию и начал "стакать" все последующие сообщения от других клиентов, как одно гигантское поле?
Нет, он съел эти 2 ГБ для хранения моего сообщения.
Если отсылать 2 параллельно с разных соединений, то съест 4 ГБ.
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
13.09.2017, 09:06 52
kolorotur, похоже, я всё напутал...
Сервер ведь на своём "дежурном" сокете прослушивает входящие соединения от клиентов и для каждого такого соединения создаёт "отдельный" сокет.
То есть никакого "стака" данных от разных клиентов в принципе не может быть.
Это ведь для клиента существует реализация своеобразного "события" от сервера,
в котором может прийти "портянка" из нескольких сообщений от сервера в виде одного соединения.
Цитата Сообщение от kolorotur Посмотреть сообщение
Нет, размер передаваемых данных соответствовал заявленному.
То есть 2 гига по сети ушло.
То есть вы ради "кспиримента" отправили серверу 2 гига данных?!
И сколько времени у вас это заняло? Час?!
Цитата Сообщение от kolorotur Посмотреть сообщение
Нет, он съел эти 2 ГБ для хранения моего сообщения.
Рискну предположить, что данные, которые вы отправили на сервак состояли преимущественно из латиницы.
Если сервер работает с юникодными строками, то не понятно, почему он съел всего 2 гига памяти.
Должно быть как минимум в 2 раза больше, ведь один байт латиницы в UTF-8 будет соответствовать двум байтам в UTF-16.
И если сервер для декодирования сообщения использует "накопление" поля в промежуточных структурах,
то "мгновенный" рабочий набор такого обработчика должен быть не менее 8 гигов!
Четыре из них - для накопления поля, четыре - займёт результирующая строка, которую это поле представляет.
Или я где-то не прав?
1
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
13.09.2017, 10:56  [ТС] 53
Цитата Сообщение от Fleder Посмотреть сообщение
Сервер ведь на своём "дежурном" сокете прослушивает входящие соединения от клиентов и для каждого такого соединения создаёт "отдельный" сокет.
Ну конечно — обычное TCP-соединение.

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

Цитата Сообщение от Fleder Посмотреть сообщение
То есть вы ради "кспиримента" отправили серверу 2 гига данных?!
Ну да, а в чем проблема?

Цитата Сообщение от Fleder Посмотреть сообщение
И сколько времени у вас это заняло? Час?!
Несколько секунд — у меня копия сервера на локалке стоит для разработки и тестирования

Цитата Сообщение от Fleder Посмотреть сообщение
Рискну предположить, что данные, которые вы отправили на сервак состояли преимущественно из латиницы.
Правильное предположение. Цель теста была послать большое сообщение, а не проверить возможность сервака обрабатывать юникод (он это умеет)

Цитата Сообщение от Fleder Посмотреть сообщение
Должно быть как минимум в 2 раза больше, ведь один байт латиницы в UTF-8 будет соответствовать двум байтам в UTF-16.
Сервер не на дотнете написан, что он там со строками делает — понятия не имею.
Возможно, он сообщения хранит в UTF-8 в памяти или вообще как просто байты и интерпретирует по надобности.
Отправил 2 гига двухбайтового текста, потребляемая память доросла до 2ГБ, потом буквально на секунду резко скакнула до 4ГБ и обратно до 2. Мутит он что-то

Цитата Сообщение от Fleder Посмотреть сообщение
"мгновенный" рабочий набор такого обработчика должен быть не менее 8 гигов!
Четыре из них - для накопления поля, четыре - займёт результирующая строка, которую это поле представляет.
Если на дотнете с его 16-битными символами, то да. Но по факту дорастает до 2, потом резко прыгает до 4 и снова падает до 2.
0
263 / 224 / 108
Регистрация: 09.12.2015
Сообщений: 652
13.09.2017, 11:16 54
Цитата Сообщение от kolorotur Посмотреть сообщение
Отправил 2 гига двухбайтового текста, потребляемая память доросла до 2ГБ, потом буквально на секунду резко скакнула до 4ГБ и обратно до 2. Мутит он что-то
Возможно, этот двухкратный скачок потребления памяти связан с тем,
что сервер сначала накапливает поле в чанках (как это делает "новый" StringBuilder в C# (с .NET 4.0)),
потом выделяет строку и копирует в неё содержимое чанков, а затем резилит и сами чанки.
Наверное, сервер на плюсах и использует ansi строки.
1
13.09.2017, 11:16
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.09.2017, 11:16
Помогаю со студенческими работами здесь

Отправка сообщений на почту по протоколу SMTP без использования .NET-функций
Всем привет. Такая проблема.Требуется написать программу, которая будет отсылать на почту сообщения...

Ваша идея, моя реализация
Хочется попрактиковаться в написании программ с использованием wxWidgets. Если проще - речь идет о...

Моё творчество - ваша реализация
Вероятно, подобное название подошло бы для очередного организатора проекта, но я всё же выступаю в...

Нужны примеры реализации передачи сообщений по tcp протоколу, только суть, ничего лишнего
Здравствуйте, уважаемые форумчане! Искал примеры реализации передачи сообщений по tcp протоколу,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
54
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru