Здравствуйте, CreatorCray, Вы писали:
CC>Зависит от требований к размеру пакета. Если не критично +2 байта на строку для ее размера (1 байт ИМХО слишком большая экономия, все же 255 символов для строки это не так и много, + заклад на будущее потенциальное расширение формата) то вполне стоит хранить в пакете длинну строки.
Длинну можно хранить в виде сжатого int32, как это делает .NET-ный BinaryWriter. Т.е. если длиннна < 128 то, 1 байт, от 128 до ~32K — 2 байта ...
Если интересует, могу скопировать алгоритм сжатия/разжатия из Reflector-a.
Здравствуйте, Sergey J. A., Вы писали:
SJA>Здравствуйте, CreatorCray, Вы писали:
CC>>Зависит от требований к размеру пакета. Если не критично +2 байта на строку для ее размера (1 байт ИМХО слишком большая экономия, все же 255 символов для строки это не так и много, + заклад на будущее потенциальное расширение формата) то вполне стоит хранить в пакете длинну строки.
SJA>Длинну можно хранить в виде сжатого int32, как это делает .NET-ный BinaryWriter. Т.е. если длиннна < 128 то, 1 байт, от 128 до ~32K — 2 байта ...
SJA>Если интересует, могу скопировать алгоритм сжатия/разжатия из Reflector-a.
Да он и так элементарно пишется. Банальный алго : пока не прочитано 4 байта и старший бит прочитанного байта = 1 — читаем следующий
Вот только надо ли уж ТАК экономить?
Здравствуйте, CreatorCray, Вы писали:
SJA>>Если интересует, могу скопировать алгоритм сжатия/разжатия из Reflector-a. CC>Да он и так элементарно пишется. Банальный алго : пока не прочитано 4 байта и старший бит прочитанного байта = 1 — читаем следующий CC>Вот только надо ли уж ТАК экономить?
Это уж решать автору, ему задача извесна лучше. Я просто предложил как вариант.
Здравствуйте, ThreeD, Вы писали:
TD>Добрый день. TD>Возник такой вопрос, два разработчика пишут клиент-серверное приложение, один пишет сервер — другой клиент.
Значит, данные передаются по сети (например по TCP)? В таком случае во-первых надо обговорить какой-то стандартный маршаллинг всех данных, а не только строк. У вас же наверняка передаются не только строки. Почему бы не перестать изобретать велосипед и не применить что-то стандартное? На XDR, например (это маршаллинг классического Sun RPC) даже RFC есть.
TD> Сервер пишется на C++ а клиент на паскале (делфи). Возник спор — какой формат строк использовать или что лучше в данном приложении. дело в том что в паскале строки записываются в пакет в формате [длина строки] + [строка без 0 символа], а в си строки в формате [строка + 0 символ]. И вот при согласовании формата пакетов возник такой спор — каждый настаивает что нужно использовать именно "его" формат.
Не надо ни тот ни другой. Если выбран какой-то стандартный маршаллинг (см. мой предыдущий абзац) — надо пользоваться им. Нет — использовать что-то доморощенное, но пригодное со всех точек зрения. Например, есть так называемый netstring : длина в текстовом виде в десятичной записи, знак ':' и содержимое. (Хотя это всего лишь переделанная константа Холлерита) Пример: "abc" будет передаваться как "3:abc", а "Hello world!\n" — "13:Hello world!'\n" Чем хорош netstring — ничтожные затраты на синтаксис и при этом простой парсинг глазами в протоколе. Недостатки начинаются только когда надо передавать куски не зная заранее полную длину... ну так на это разве что ASN.1'овские форматы годятся.
TD>Паскалист привел такие доводы: TD>[q] TD>По 2-м причинам. 1-е скорость. Копровать Сишные строки из одного буффера в другой медленней чем паскалевскую строку из одного буффера в другой и диже копирование паскалевской строки из одного буффера в сишный вариант в другой буффер (конвертация на лету). Объясняю: TD>Принцип копирования строки типа Си: TD>Пусть даны 2-е строки s1 и s2 в s1 записанно "Привет#0" (7 байт) Размер s2 пока не известен (считаем что динамически выделяем память). Тогда надо посчитать длинну s1: проверить каждый байт на #0 и если нет — увеличить счётчик. Как только посчитали — сделать getmem на s2 (или malloc) и скопировать от адреса строки до адреса строки + её длинна -1
Эта... если кто-то сейчас ещё пишет на Си так как рассказывает этот паскалист, то за такое я бы стрелял без промедления. Или, говоря в терминах Луговского, "в биореактор без права булькать". Ладно ещё курсач так написать, но серьёзное приложение — ни в коем случае.
TD>Принцип копирования строки типа Паскаль: TD>Читаем 1-й байт строки (если строка максимум 255) — это размер строки. делаем getmem (malloc) на размер+1 и копируем туда от начала строки до начала + длинна строки (-1 нету).
Что такой Паскаль как описано вымер лет 10 назад — уже рассказали. А ещё вероятно что паскалист перечитался Joel'а.
Тот тоже рассказывает про "алгоритм Шлемиеля", и в общем достаточно справедливо, но опять же — где такое найти сейчас?
TD>в свою очередь другой ссылается, что ему не удобны такие строки, потомучто у себя он их будет конвертировать в сишный формат, там использовать, потом обратно перед отправкой пакета переконвертировать и терять скорость работы.
А то ему остальные данные не конвертировать?
TD> + поддержка длинных строк более 255 символов вызывает большое сомнение у него (2 байта потребует для указания длины). TD>Подскажите, что лучше всетаки использовать сишные строки или паскалевские?
Здравствуйте, Left2, Вы писали:
S>>З.Ы. Надо полагать, братанам попала 273 часть вторая, и они пытались совершить побег? Не могу придумать другого места, где они могли провести 15 лет в столь хорошей изоляции от внешнего мира.
L>
L>Статья 273. Создание, использование и распространение вредоносных программ для ЭВМ
L>1. Создание программ для ЭВМ или внесение изменений в существующие программы, заведомо приводящих к несанкционированному уничтожению, блокированию, модификации либо копированию информации, нарушению работы ЭВМ, системы ЭВМ или их сети, а равно использование либо распространение таких программ или машинных носителей с такими программами —
L>наказываются лишением свободы на срок до трех лет со штрафом в размере до двухсот тысяч рублей или в размере заработной платы или иного дохода осужденного за период до восемнадцати месяцев.
L>2. Те же деяния, повлекшие по неосторожности тяжкие последствия, —
L>наказываются лишением свободы на срок от трех до семи лет.
L>Нда... Разве что если они взломали тюремный компьютер и добавили себе срок... L>)
Несколько попыток совершить побег — только и всего.
Но лично у меня другая гипотеза:
Учитывая то, что последенее время в философии регулярно появляются темы про ASCIIZ строки и про скорость с использованием классов или без, то в общем то все ясно. Где-то открылся хроносинкластический инфиндибулум через который в наше время попала группа программистов из 1985го года.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
L>наказываются лишением свободы на срок от трех до семи лет.
L>Нда... Разве что если они взломали тюремный компьютер и добавили себе срок... L>) S>>З.Ы. Надо полагать, братанам попала 273 часть вторая, и они пытались совершить побег?
См. выделенное
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, ThreeD, Вы писали:
TD>Возник такой вопрос, два разработчика пишут клиент-серверное приложение, один пишет сервер — другой клиент. Сервер пишется на C++ а клиент на паскале (делфи). Возник спор — какой формат строк использовать или что лучше в данном приложении. дело в том что в паскале строки записываются в пакет в формате [длина строки] + [строка без 0 символа], а в си строки в формате [строка + 0 символ]. И вот при согласовании формата пакетов возник такой спор — каждый настаивает что нужно использовать именно "его" формат.
Хочу обратить внимание коллег, что здесь идёт речь не о том, как хранить строки на каждой стороне (и в дельфи, и в с++ есть как нормальные и удобные средства, так и возможность для велосипедостроения). А об интеропе. Как обоюдо-удобнее сериализовать.
И вот здесь, очевидно, строки с префиксом длины рулят и побеждают почти при любом раскладе.
Пакеты у нас имеют переменную длину (надеюсь, мы не станем повторять ошибок паскалистов 70-х — 80-х, которые побайтово сериализовывали record с несколькими string[255], т.е. передавали за компанию кучу мусора).
Записать пакет можно любым способом
— строку плюс маркер конца (любой: хоть NUL для ASCII, хоть ++ для Base64) чуть легче (потому что нам не нужно измерять длину); правда, маркер должен быть различим, и если его алфавит пересекается с основным алфавитом — придётся делать посимвольный кодировщик
— длину плюс строку чуть тяжелее, если контейнер строки вычисляет длину через strlen (т.е. сишник ищет приключения на свою голову)
А читать...
— строку с маркером — нам потребуется динамический массив, куда мы станем накапливать результат, пока не дойдём до маркера; либо файл с произвольным доступом и двухпроходное чтение (читаем до маркера, выделяем память и читаем известное количество символов)
— строку с префиксом — читаем от 1 до 4 байт длины (префикс может быть переменного размера, но согласитесь, это не то же самое, что динамический массив), выделяем память и читаем данные.
Кстати говоря, на длину строки может быть наложено ограничение. Ну например, MAX_PATH.
А если строки заведомо маленькие, то и в фиксированных пакетах можно передавать, и с маркерами конца. Критерий "маленькости" — на усмотрение разработчиков. Ну скажем, 32 символа — это очень маленькая строка. До 1024 — с маркером потянет (будем читать в статический буфер), а в фиксированный пакет уже жалко. В районе 2^16 жаба задавит.
Здравствуйте, ThreeD, Вы писали:
TD>Вопрос видимо сводится к тому в каком формате передавать строки в пакете: указывать ли перед строкой ее длину, а саму строку без 0 в конце, или передавать стандартные строки с 0 в конце. Со стороны сервера без разницы как придет строка (просто будет несколько лишних операций по считыванию этой длины а потом самой строки или за 1 проход в случае стандартной строки). При запись ответа от сервера — опять определение длины строки, потом запись в пакет самой строки за вычетом 0. А сами строки на сервере будут использоваться через std::string. Сервер расчитывается на подключении нескольких тысяч клиентов одновременно. Вот и хочется занть как лучше передавать строки в пакете — в паскалевском или в сишном формате, как быстрее будет и удобнее (сервер на СИ)
Так на С или С++?
std::string::size() вычисляется за O(1) — так что писать префикс ничуть не дороже, чем маркер конца.
А считывать — тоже не проблема. Прочли длину, зарезервировали память в строке и прочитали одним махом без переразмещения. Вот посимвольное считывание до маркера — там да, будет весело.
Владек wrote: > TD>Подскажите, что лучше всетаки использовать сишные строки или > паскалевские? > А почему бы не использовать гибрид: два байта с указанием длины впереди > и заверщающий нулевой байт?
Примерно так и устроен std::string и BSTR.
Здравствуйте, Cyberax, Вы писали:
>> А почему бы не использовать гибрид: два байта с указанием длины впереди >> и заверщающий нулевой байт? C>Примерно так и устроен std::string и BSTR.
Здравствуйте, Владек, Вы писали: В>А почему бы не использовать гибрид: два байта с указанием длины впереди и заверщающий нулевой байт? Re[4]: Какие строки лучше использовать