Использовать компоненты сторонних разработчиков было нельзя. Shared memory предполагалось использовать для сортировки текстовых файлов больших размеров – несколько десятков или даже сотен мегабайт, на которых TStringList падал с EOutOfMemory. Pipes – для передачи файлов от одного приложения другому.
Переписать код примеров из документации Microsoft с C на Delphi – это было даже не полдела, а процентов 10. Главное было связать это все вместе, дописать, где нужно, дополнительные функции и заставить всё это работать, а не просто существовать в виде исходного кода. В результате родился такой уродливый монстр, что его не то, что показывать кому-то, а просто смотреть на него было страшно. Однако, может, кто-то найдет в его недрах что-то для себя полезное (а вдруг?), поэтому я решил его здесь выложить. На всеобщее поругание. Полный исходный код этой abomination выложен на GitHub. В тексте статьи будут даны названия файлов, где можно посмотреть тот или иной кусок реализации.
Первая задача – сортировка текстового файла – решалась так:
- Открываем файл (CreateFile).
- Используем CreateFileMapping и MapViewOfFile (common\MemoryMappedFileUnit.pas).
- Определяем кодировку файла. Здесь я ограничился, по сути, только двумя кодировками: UTF-16 и ACP – однобайтовая кодировка с кодовой страницей по умолчанию. В русскоязычной Windows обычно используется Windows-1251.
- Разбиваем текст на строки. То есть ищем маркеры конца строк и, соответственно, считаем текст от маркера до маркера одной строкой.
- Сортируем полученный массив строк (SortingTest\MergeSorterUnit.pas).
- Записываем отсортированный массив строк обратно в файл.
- PROFIT!
Сортировку заказчик обязательно хотел сделать многопоточной, поэтому в качестве алгоритма сортировки была взята Merge Sort. (Спасибо тому гуру, который создал рабочую реализацию и выложил ее на Stackoverflow.)
Вторая задача – передача файла от одного приложения к другому – оказалась куда сложнее. Получить реализацию pipes на Delphi на основе примеров Microsoft – это одно, но сделать из нее рабочую передавалку файлов – совсем другое. В качестве программы-сервера Microsoft предлагает несколько вариантов:
- Multithreaded Pipe Server.
- Named Pipe Server Using Overlapped I/O.
- Named Pipe Server Using Completion Routines.
Как выяснилось в результате двухнедельных мучений, реализация механизма передачи файла на основе первого варианта сервера (Multithreaded Pipe Server) у меня вышла слишком сложной. Второй вариант (Named Pipe Server Using Overlapped I/O) получился намного проще (правда, заказчик по каким-то своим причинам очень хотел именно первый вариант сервера). Но всё равно пришлось помучиться, чтобы довести всё это дело до ума. В результате родился передатчик файлов на основе pipes: TCommunicationEndpointBase (CommunicationTest\SimpleCommunicationUnit.pas).
Вкратце, передача файлов работает так:
- Создаем сервер, то есть создаем named pipe.
- Создаем клиент, который подключается к этому named pipe.
- Крутим цикл «посылаем запрос – ждем ответ – читаем ответ» на клиенте и на сервере.
- Большие файлы посылаем частями и потом собираем файл из этих кусочков.
- По окончании передачи файлов закрываем соединение.
Все нюансы реализации можно посмотреть на GitHub, где выложен полный код всего вышеперечисленного. Всё оформлено в виде одного приложения (BlitzTest\BlitzTest.dproj), достаточно его скачать, собрать и запустить.
Да, еще там до кучи лежит оптимизированная реализация функции StringReplace (BlitzTest\StringReplaceCustomUnit.pas). Может, кому пригодится.
Любые комментарии (в том числе и откровенная ругань) приветствуются.
Если вдруг (ну, а вдруг?) кого-то заинтересуют другие мои репозитории, то могу и о них пару слов написать. Если, конечно, этот текст вообще опубликуют.
gFanis
Неплохо.
На сайте overbyte.eu есть ветка MIDWARE — я использовал изложенные автором идеи для реализации подобного обмена.
ShaltaiBoltai Автор
Да, разумеется, в сети много всего есть: есть и готовые решения. Я сразу говорю: мне была поставлена задача это всё дело реализовать без использования готовых решений. Так было нужно заказчику — не столько качество, сколько чего-то другое. Так что, мое решение в силу этого тоже далеко не самое оптимальное: тем более, заказчик по итогам всё равно от него отказался вообще. А я решил его выложить, чтоб труд за зря не пропадал. Может, кто-то найдет в этой куче кода что-то для себя полезное.
SpiderEkb
Повторюсь еще раз. На майлслотах все это делается куда проще… Описание в MSDN есть. Подробное и с примерами.
Там не требуется создание сервера, отслеживание соединения и все такое. Просто нужно создать майлслот и проверять, не закинул ли туда кто-нибудь чего-нибудь полезное (типа ножки для стола (с) :-)
В целом MailSlot и Pipe это как UDP и TCP сокеты.
Ну и ваш пример весьма показателен для современного мира — любители фреймворков живут исключительно внутри своих фремворков и очень слабо себе представляют возможности и API платформы, под которой они работают. Выход за пределы фреймворка сопровождается острым приступом агаророфобии.
ShaltaiBoltai Автор
Я не понял, о какой агаророфобии вы говорите, и о каких любителях, так что буду трактовать ваши слова вольно. Если применить их к тем, о ком я думаю, то вы, вероятнее всего, где-то правы.
SpiderEkb
Ну попробую перефразировать. Долго работал под Win. Ну и общался с себе подобными. Среди них было немало людей, писавших на VCL (Дельфи и Билдер). Так вот значительная часть из них была ограничена исключительно рамками того, что предоставляет VCL. И если там чего-то нет, то все, «это невозможно потому что этого нет в VCL». Какие возможности предоставляет WinAPI они понятия не имеют — для них это темный лес, страшно и непонятно. Что такое MSDN (на мой взгляд, одна из лучших справочных систем) ни разу не слышали.
То, что в некоторых случаях эффективнее сделать свою библиотечку (а она получается очень компактной), содержащей UDP и TCP сокеты и TCP сервер для работы в синхроне в отдельном потоке для них просто откровение — люди не представляют что такое WINSOCKS и как с ним работать.
Про ряд интересных функций, которых нет в стандартных заголовках (но они описаны в MSDN и «достаются» через GetProcAddress) уж и говорить не стоит…
Вот это и есть агарофобия — в данном случае паническая боязнь выйти за пределы фреймворка на просторы системного API.
ShaltaiBoltai Автор
Значит, я правильно вас понял. Да, всё именно так и есть. У меня сложилось точно такое же представление о «делфийском народе».
SpiderEkb
Ну не только делфиском. На билдере все примерно также… Стремление быстро слепить продукт из VCL компонентов, не вдаваясь в детали. Это обратная сторона «низкого порога вхождения», о котором так часто упоминалось в обсуждениях Делфи.
Есть ощущение, что подобное и в других областях наблюдается (та же мобильная разработка — скорее схватить самый модный на текущий момент фреймворк и вперед — к монетизации своего приложения).
Я сам продолжительное время на билдере работал, но начинал еще под досом, с Turbo C 1.0 Б потом 2.0, Turbo C++, Borland C++ — 4-я версия была невозможно глючной, с нее ушел на MSVC и потом уже вернулся на билдер 6-й.
Помню что когда с доса на вин переходил, первое приложение написал на чистом WinAPI. Просто чтобы понимать как оно работает. Ну и в билдере не боялся апишные функции использовать там, где по каким-то причинам VCL не устраивала или ее нехватало.
Что касается межпроцессных и межпоточных коммуникаций, то в последнем виндовом проекте этого было много и пришлось глубоко вникать в эту тему.
ShaltaiBoltai Автор
Это не «низкий порог вхождения», а особенность нашего национального постсоветского программирования, распространенного в 1990-е и ранние 2000-е.
Вот-вот — эта особенность нас, старичков. (Рассыпает песочек...)
В 1990-е у нас Delphi и ее брат-близнец CBuilder были дико популярны. Мне сложно сказать, с чем эта дикая популярность была связана (может, книги по Pascal сюда завозили бесплатно, а за все остальные книги просили денежку), но отсюда берет начало эта распространенность Delphi на нашей территории. Собственно, не будь России, Абракадабра уже давно бы загнулась — в цивилизованных странах ее продукты уже давно нахрен никому не нужны. Одни мы их еще покупаем, вот она, видимо, потому еще шевелится.
Современное же поколение программеров этой Delphi-манией уже не охвачено. Они, полагаю, даже не в курсе, что сей уродец мира программирования существует.
0xf0a00
Ой ой, а сколько желчи полилось… Расскажите мне чем писать под виндовс так что бы не блевать в процессе, так что бы все в одном и в найтиве… да да С# в пролете. Да и что бы мне не надо было собирать среду из кусков так что ее невозможно потом воспроизвести на другом ПК.
SpiderEkb
Разговор не о том на чем писать (под винды есть Visual Studio, выросшая из MSVC + MFC). Вопрос о том как писать.
Хотите писать под винду? Учите прежде всего WinAPI и те системные средства, что она предлагает. Ну и просто архитектурные решения, позволяющие понимать когда и где выгоднее использовать асинхрон в общем потоке, а когда и где — синхрон в отдельном потоке.
SpiderEkb
Современное поколение охвачено манией мобильной и ваб разработки. А там тоже фреймворки. И вопросы там «а вот этот фреймворк может это, а тот модет то». И мало кому (у меня такое впечатление) призодит в голову, что все «то» или «это» опирается на возможности платформы. А «может» или «не может» определяется исключительно тем, дошли у разработчика фреймворка руки реализовать «то» или «это», или нет.
И уж точно мало кому в голову приходит расширить фреймворк путем дописывания каких-то своих библиотек или функций.
Для себя я как-то пришел к тому, что когда чего-то нехватает, я просто дописываю это сам. А если этот кусок кода из одного проекта вдруг требуется в другом, он оформлаяется в виде библиотеки.
Долго жил под виндами. Писал на С и С++. Потом несколько лет назал в жищни случился крутой поворот и теперь я пишу под AS/400 главным образом на специфическом языке RPG (мало известен за пределами этой платформы, хотя у MS была попытка создать VisualRPG).
Язык специфический, ориентирован прежде всего на работу с БД и коммерческие рассчеты. И там совершенно нет такой вещи как списки. А я очень привык с ними работать. Даже больше, чем со статическими массивами. И очень мне их нехватало. В RPG есть указатели. И есть понятие структуры. Но все это как-то коряво там выглядит.
Но к счастью, С/С++ на этой платформие тоже поддерживается (более того, там есть концепция ILE — интегрированная языковая среда, позволяющая одну программу собирать из нескольких модулей на разных языках). Так что довольно скоро я (для себя в первую очередь, но разработка имела успех и у коллег) сделал сервисную программу (некий аналог виндовой dll) в которой было реализовано несколько алгоритмов на базе списков, которые достаточно легко можно использовать в RPG программах. Да, на это было потраченотнекоторое количество личного времени, но сейчас все это сильно упрощает разработку.
Потребуется что-то еще — будет что-то еще. Не проблема.
ShaltaiBoltai Автор
Это не «мания», это запросы рынка. Да, сейчас 80% программирования — это написание сайтов (то есть .Net Core + тонна js, как раз зоопарк этих фреймворков), 15% — это Ведроид, и на десктоп остается 5%. Мы, старички, как вид программеров вымираем. А, может, даже уже вымерли.
SpiderEkb
Ну не знаю… В процентах мне сложно судить, но три года назад достаточно много вакнсий было именно на серьезную разработку — промавтоматицация, телекоммуникации, финтех и прочие подобные вещи. Т.е. по «разработчик С/С++» вылазит очень много чего разного.
ShaltaiBoltai Автор
Разумеется, мои проценты тоже не из скрупулезного статистического исследования взяты. Так, на глазок.
Да, «разработчик C++» действительно вылазит, но объемы всё равно не сравнимы с «Full stack developer». А так много чего вылазит: Go, Rust, Java…
SpiderEkb
В целом соглашусь. Но для нас пока еще есть работа :-) И, надеюсь, еще будет. Кто-то все рано должен обеспечивать то, на что весь этот фуллстек опирается — самый нижний уровень.