Добрый день.
Возник такой вопрос, два разработчика пишут клиент-серверное приложение, один пишет сервер — другой клиент. Сервер пишется на C++ а клиент на паскале (делфи). Возник спор — какой формат строк использовать или что лучше в данном приложении. дело в том что в паскале строки записываются в пакет в формате [длина строки] + [строка без 0 символа], а в си строки в формате [строка + 0 символ]. И вот при согласовании формата пакетов возник такой спор — каждый настаивает что нужно использовать именно "его" формат.
Паскалист привел такие доводы:
По 2-м причинам. 1-е скорость. Копровать Сишные строки из одного буффера в другой медленней чем паскалевскую строку из одного буффера в другой и диже копирование паскалевской строки из одного буффера в сишный вариант в другой буффер (конвертация на лету). Объясняю:
Принцип копирования строки типа Си:
Пусть даны 2-е строки s1 и s2 в s1 записанно "Привет#0" (7 байт) Размер s2 пока не известен (считаем что динамически выделяем память). Тогда надо посчитать длинну s1: проверить каждый байт на #0 и если нет — увеличить счётчик. Как только посчитали — сделать getmem на s2 (или malloc) и скопировать от адреса строки до адреса строки + её длинна -1
Принцип копирования строки типа Паскаль:
Читаем 1-й байт строки (если строка максимум 255) — это размер строки. делаем getmem (malloc) на размер+1 и копируем туда от начала строки до начала + длинна строки (-1 нету).
Принцип копирования из строки типа паскаль в строку типа Си:
Читаем 1-й байт. Делаем getmem(malloc) копируем от начала +1 до начала +длинна и в начало +длинна +1 ставим #0
Скорость очевидна. Теперь рассмотрим если буффер для s2 уже задан (в строке типа СИ):
начинается самое интересное. Пусть под s2 уже выделенно 100 байт, тогда копирование проводится следующем образом: копируется каждый байт из s1 в s2 со смещением до тех пор, пока не будет #0 оно копируется и процесс завершается.
Здаесь есть одно бальшое НО: Есл s1 больше 100 байт то мы выйдем за приделы буффера и будем копировать уже поверх программы (так как в Си данные можно объявить где хочешь)... По идеи получем GPF, но на самом деле не всегда... Если после 100 значения будет уже скомпилированный код, то файкически он будет выполняться. Это и есть атака на переолнения буффера. Это вторая причина. Из метода копирования ясно, что при работе с паскалевскими строками такой атаки быть не может просто! Конечно есть способ и в Си, позволяющий обойти эту ататку щас я его расскажу:
При копировании из s1 в s2 ведётся счётчик и если он =100 то в s2 записывается #0 и копирование обрывается. Или идет увеличение буффера.
ЗЫ: основная проблема Си строк(да и вообще с любыми строками) это то что всегда прежде чем работать с ними нужна их длинна, а она и Си строках очень долго определяется.
По поводу Паскалевских строк. Ситы утверждают что можно "насрать" в 1-й байт. Да можно, но если его уменьшить — данные просто потеряются, есл увеличить — это будет часть строки, НО ОНО НИКОГДА НЕ БУДЕТ ВЫПОЛНЯТЬСЯ!!!!
В приведённых выше примерах я, кажется, разобрал все способы и при том защищенное копирование строк в Си делается способом занимающем больше времени (этот алгоритм оптимизирован), а если хранить длинну строки в Си... то смысл? тогда это будет паскалевская строка с #0 сзади.
Если непонятно — могу привести код на ассемблере для пояснения.
Из всего вышесказанного: паскалевские строки и быстрее и надежнее. А выигрыш по памяти при работе с короткими строками (до 255) вообще никакой.
в свою очередь другой ссылается, что ему не удобны такие строки, потомучто у себя он их будет конвертировать в сишный формат, там использовать, потом обратно перед отправкой пакета переконвертировать и терять скорость работы. + поддержка длинных строк более 255 символов вызывает большое сомнение у него (2 байта потребует для указания длины).
Подскажите, что лучше всетаки использовать сишные строки или паскалевские?
Здравствуйте, ThreeD, Вы писали:
TD>Возник такой вопрос, два разработчика пишут клиент-серверное приложение, один пишет сервер — другой клиент. Сервер пишется на C++ а клиент на паскале (делфи). Возник спор — какой формат строк использовать или что лучше в данном приложении. дело в том что в паскале строки записываются в пакет в формате [длина строки] + [строка без 0 символа], а в си строки в формате [строка + 0 символ]. И вот при согласовании формата пакетов возник такой спор — каждый настаивает что нужно использовать именно "его" формат. TD>Паскалист привел такие доводы:
Прошу прощения, но кажется, то что говорит паскались уже несколько лет как неверно: начиная с какой-то версии строки в дельфи — по умолчанию null-terminated.
Здравствуйте, ThreeD, Вы писали:
TD>По 2-м причинам. 1-е скорость. Копровать Сишные строки из одного буффера в другой медленней чем паскалевскую строку из одного буффера в другой и диже копирование паскалевской строки из одного буффера в сишный вариант в другой буффер (конвертация на лету).
Экономим на спичках? Ничто не мешает использовать std::string у которого размер хранится в строке и он safe в отношении криворукости программера при копировании строк.
TD>По поводу Паскалевских строк.
хранить размер в первом байте — ИМХО через задницу. Если хочется хранить — то уж лучше класс а-ля std::string.
TD>Из всего вышесказанного: паскалевские строки и быстрее и надежнее.
false
TD>Подскажите, что лучше всетаки использовать сишные строки или паскалевские?
Для интерконнекта ИМХО формат пакета должен задавать сервер. И уж клиенты должны подстраиваться.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
CreatorCray wrote: > TD>По 2-м причинам. 1-е скорость. Копровать Сишные строки из одного > буффера в другой медленней чем паскалевскую строку из одного буффера в > другой и диже копирование паскалевской строки из одного буффера в сишный > вариант в другой буффер (конвертация на лету). > Экономим на спичках? Ничто не мешает использовать std::string у которого > размер хранится в строке и он safe в отношении криворукости программера > при копировании строк.
Кстати, и при формировании строки std::string будет быстрее, так как
позволяет зарезервировать место заранее.
Здравствуйте, Lloyd, Вы писали:
L>Прошу прощения, но кажется, то что говорит паскались уже несколько лет как неверно: начиная с какой-то версии строки в дельфи — по умолчанию null-terminated.
Вот чел который пишет клиент (на паскале) с пеной у рта доказывает что так, паскаль умеет вроде в сишный формат, но он этого не будет, потомучто якобы строки в паскалевском формате копируются быстрее и безопаснее.
Поэтому клиент должен принимать пакеты где строки в этом формате и никак иначе. Только сервер с ними работать не будет, а будет всеравно конвертить из одного в другое а потом обратно. ИМХО это не верно, но чел уперся. Вот поэтому хотим услышать ваше мнение, чтобы разрешить конфликт этот.
TD>Вот чел который пишет клиент (на паскале) с пеной у рта доказывает что так, паскаль умеет вроде в сишный формат, но он этого не будет, потомучто якобы строки в паскалевском формате копируются быстрее и безопаснее. TD>Поэтому клиент должен принимать пакеты где строки в этом формате и никак иначе. Только сервер с ними работать не будет, а будет всеравно конвертить из одного в другое а потом обратно. ИМХО это не верно, но чел уперся. Вот поэтому хотим услышать ваше мнение, чтобы разрешить конфликт этот.
Ну не перевирай... Я пытаюсь объяснить что в пакете передичи надо держать длинну у строки а не по #0 её обрывать.
Здравствуйте, ThreeD, Вы писали:
TD>Вот чел который пишет клиент (на паскале) с пеной у рта доказывает что так, паскаль умеет вроде в сишный формат, но он этого не будет, потомучто якобы строки в паскалевском формате копируются быстрее и безопаснее. TD>Поэтому клиент должен принимать пакеты где строки в этом формате и никак иначе. Только сервер с ними работать не будет, а будет всеравно конвертить из одного в другое а потом обратно. ИМХО это не верно, но чел уперся. Вот поэтому хотим услышать ваше мнение, чтобы разрешить конфликт этот.
Пусть просто произведет замеры. Но не в синтетическом тесте, а хотя бы чуть-чуть приближенном к реальности. Тогда он увидит, что принцыпиальной разницы в производительности не будет.
Здравствуйте, CreatorCray, Вы писали: CC>Экономим на спичках? Ничто не мешает использовать std::string у которого размер хранится в строке и он safe в отношении криворукости программера при копировании строк.
Вот и я про то-же. А теперь давайте подумаем чем отличается этот тип строки от паскалевской? Ага... #0 сзади (причем наверно, так как я туда не смотрел) И что мешает ему в пакете сначала прочитать длинну строки, а потом брать строчку (а ведь имеено из-за этого весь сыр-бор)
Здравствуйте, Warstone, Вы писали:
W>Ну не перевирай... Я пытаюсь объяснить что в пакете передичи надо держать длинну у строки а не по #0 её обрывать.
Зависит от требований к размеру пакета. Если не критично +2 байта на строку для ее размера (1 байт ИМХО слишком большая экономия, все же 255 символов для строки это не так и много, + заклад на будущее потенциальное расширение формата) то вполне стоит хранить в пакете длинну строки.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Warstone, Вы писали:
W>Здравствуйте, CreatorCray, Вы писали: CC>>Экономим на спичках? Ничто не мешает использовать std::string у которого размер хранится в строке и он safe в отношении криворукости программера при копировании строк.
W>Вот и я про то-же. А теперь давайте подумаем чем отличается этот тип строки от паскалевской? Ага... #0 сзади (причем наверно, так как я туда не смотрел) И что мешает ему в пакете сначала прочитать длинну строки, а потом брать строчку (а ведь имеено из-за этого весь сыр-бор)
Все равно это не чистый паскалевский формат записи будет.
Предлагаю что нить типа:
WORD stringSize — 2 байта на размер строки включая \0 в конце
ASCIIZ string — zero-tеrminated строка
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Вопрос видимо сводится к тому в каком формате передавать строки в пакете: указывать ли перед строкой ее длину, а саму строку без 0 в конце, или передавать стандартные строки с 0 в конце. Со стороны сервера без разницы как придет строка (просто будет несколько лишних операций по считыванию этой длины а потом самой строки или за 1 проход в случае стандартной строки). При запись ответа от сервера — опять определение длины строки, потом запись в пакет самой строки за вычетом 0. А сами строки на сервере будут использоваться через std::string. Сервер расчитывается на подключении нескольких тысяч клиентов одновременно. Вот и хочется занть как лучше передавать строки в пакете — в паскалевском или в сишном формате, как быстрее будет и удобнее (сервер на СИ)
Здравствуйте, ThreeD, Вы писали:
TD>Вопрос видимо сводится к тому в каком формате передавать строки в пакете: указывать ли перед строкой ее длину, а саму строку без 0 в конце, или передавать стандартные строки с 0 в конце. Со стороны сервера без разницы как придет строка (просто будет несколько лишних операций по считыванию этой длины а потом самой строки или за 1 проход в случае стандартной строки). При запись ответа от сервера — опять определение длины строки, потом запись в пакет самой строки за вычетом 0. А сами строки на сервере будут использоваться через std::string. Сервер расчитывается на подключении нескольких тысяч клиентов одновременно. Вот и хочется занть как лучше передавать строки в пакете — в паскалевском или в сишном формате, как быстрее будет и удобнее (сервер на СИ)
Лучше в паскалевском [размер][строка]
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Что-то я не вижу, как формат строки в пакете данных зависит от языка программирования.
Я всегда для передачи через TCP использовал формат с размером строки в начале. Хоть в C, хоть в C#, хоть в Delphi. Просто потому, что такие строки удобнее принимать (читаем размер, потом строку):
What a piece of work is a man! how noble in reason! how infinite in faculty! in form and moving how express and admirable! in action how like an angel! in apprehension how like a god! the beauty of the world! the paragon of animals!
Так в Дельфи, если мне не изменяет память, этот вопрос был с первой или второй версии решен. Со смещением -4 хранится длина, сама строка заканчивается 0.
Здравствуйте, ThreeD, Вы писали:
TD>Добрый день. TD>Возник такой вопрос, два разработчика пишут клиент-серверное приложение, один пишет сервер — другой клиент. Сервер пишется на C++ а клиент на паскале (делфи). Возник спор — какой формат строк использовать или что лучше в данном приложении. д
Лучше не путать формат пакета данных с форматами строк клиента и сервера
Передавайте строки как вам угодно и конвертируйте на обеих сторона если надо. Если хотите выбрать формат сетевых пакетов, то надо спрашивать не программеров клиента и сервера, а проектировщика протокола. Обычно по сети удобнее передавать данные с заранее указанной длиной.
Здравствуйте, CreatorCray, Вы писали: CC>Все равно это не чистый паскалевский формат записи будет. CC>Предлагаю что нить типа:
CC>WORD stringSize — 2 байта на размер строки включая \0 в конце CC>ASCIIZ string — zero-tеrminated строка
Ну надо же. Еще немного, и вы изобретете борландовский AnsiString.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, ThreeD, Вы писали:
TD>Добрый день. TD>Возник такой вопрос, два разработчика пишут клиент-серверное приложение, один пишет сервер — другой клиент. Сервер пишется на C++ а клиент на паскале (делфи). Возник спор — какой формат строк использовать или что лучше в данном приложении. дело в том что в паскале строки записываются в пакет в формате [длина строки] + [строка без 0 символа], а в си строки в формате [строка + 0 символ]. И вот при согласовании формата пакетов возник такой спор — каждый настаивает что нужно использовать именно "его" формат. TD>Паскалист привел такие доводы:
Паскалиста немедленно уволить за некомпетентность. Сишника отправить на курсы повышения квалификации.
Причины:
1. Паскаль, который использовал первый байт строки для хранения длины, умер более 10 лет назад. Все 32-разрядные Delphi, естественно, хранят длину в 32-разрядном интегере.
2. Delphi, естественно, заканчивает все свои строки нулем. Для того, чтобы легче было интероперировать с C и С++.
3. Сишника нужно срочно обучить C++ и заставить забыть ASCIIZ как страшный сон. Потому как даже если лично он умеет бороться с ликами и buffer overrun-ами, то никто не сможет обеспечивать это при внесении изменений в его код. В плюсах уже давно можно использовать стандартные безопасные строковые классы, а уж единожды написать конвертер для такой строки в какой бы то ни было формат пакета для программиста проблемы представлять не должно.
З.Ы. Надо полагать, братанам попала 273 часть вторая, и они пытались совершить побег? Не могу придумать другого места, где они могли провести 15 лет в столь хорошей изоляции от внешнего мира.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>З.Ы. Надо полагать, братанам попала 273 часть вторая, и они пытались совершить побег? Не могу придумать другого места, где они могли провести 15 лет в столь хорошей изоляции от внешнего мира.
Статья 273. Создание, использование и распространение вредоносных программ для ЭВМ
1. Создание программ для ЭВМ или внесение изменений в существующие программы, заведомо приводящих к несанкционированному уничтожению, блокированию, модификации либо копированию информации, нарушению работы ЭВМ, системы ЭВМ или их сети, а равно использование либо распространение таких программ или машинных носителей с такими программами —
наказываются лишением свободы на срок до трех лет со штрафом в размере до двухсот тысяч рублей или в размере заработной платы или иного дохода осужденного за период до восемнадцати месяцев.
2. Те же деяния, повлекшие по неосторожности тяжкие последствия, —
наказываются лишением свободы на срок от трех до семи лет.
Нда... Разве что если они взломали тюремный компьютер и добавили себе срок...