Глубины Indy

         

Параллельное выполнение


Параллельное выполнение – это состояние, когда много задач возникает в одно и тоже время. Когда конкурирование реализовано правильно это может рассматривать как «гармония», а если плохо, то как «хаос» .

В большинстве случаев, задача выполняется в потоке (thread). Но также это могут быть процессы (process) или волокна (fiber). Разделение очень условное, но использование правильной адстракции является ключем к успеху.



Параллельное выполнение (Concurrency)


В многопоточной среде ресурсы должны быть защищены так, чтобы они не были разрушены при одновременном доступе.

Параллельное выполнение и потоки переплетаются и выбор, что изучать сначала может быть сложным. В данном разделе мы рассмотрим параллельное выполнение и попытаемся дать понятия для изучения потоков.



Перехватчики


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

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

Клиентские перехватчики базируются на соединениях (по одному на каждое). Они также могут быть использованы на сервере, если они назначены индивидуальному соединению.

Примечание: Перехватчики в Indy 9 отличаются от перехватчиков в Indy 8. Перехватчики в Indy 8, выполняли комбинированную роль перехватчика и обработчика ввода/вывода. Что делало сложным разделение функций перехвата и обработки. Перехватчики Indy 8 также не могли изменять размер данных и поэтому были непригодны для сжатия.



Перехватчики (Intercepts)


Перехватчик – это более высокий уровень, чем обработчик ввода/вывода и используется для модификации или перехвата данных независимо от источника и приемника.

Перехватчики были сильно изменены в версии 9.0. В версии 8.0 перехватчик мог предоставлять только весьма ограниченную функциональность обработчика ввода/вывода. Перехватчики могут трансформировать уже принятые данные или данные для передачи. Перехватчики более не поддерживают никакой функциональности обработчика ввода/вывода (IOHandler), поскольку введены новые классы IOHandler, со всей необходимой  функциональностью.

Перехватчики попрежнему могут выполнять преобразования данных и но предоставляют больше возможностей в Indy 9.0. Возможности трансформация в Indy 8.0 были сильно ограничены, так как данные должны были иметь один и тот же размер. Это делало невозможным использовать их для реализации сжатия данных или логирования, поскольку не позволяло изменить размер данных.

Перехватчики позволяют изменять данные после того, как они были приняты в IOHandler или изменять их перед посылкой в IOHandler. Перехватчики в данный момент используются для реализации ведения логов и отладки компонент. Они могут быть также использованы для реализации шифрования, сжатия, статических коллекторов или ограничитения трафика.



Переменные потоков


Переменные потока объявляются с использование ключевого слова ThreadVar.

Переменные потока подобны глобальным переменным и объявляются подобным образом. Различие в том, что обычная глобальная переменная является глобальной для всех потоков, а переменные потока специфичны для каждого потока. Так в каждом потоке, появляется  свое собственное глобальное пространство.

Переменные потока могут быть полезны, когда трудно передавать ссылки на объект между библиотеками или изолированными кусками кода. Конечно переменные потока имеют и ограничения. Переменные потока не могут быть использованы или объявлены внутри пакетов. Везде где только возможно, должны быть использованы члены-переменные в классе потока. Они обеспечивают меньшую нагрузку и доступны для использования в пакетах.



Переработка обработчиков ввода/вывода (IOHandler)


Для получения улучшения производительности в Indy 10 были переработаны обработчики ввода/вывода и им была придана более весомая роль. Ранее роль обработчиков ввода/вывода состояла только в очень базовой обработке ввода/вывод и относилась к следующим функциям:

Open (Connect) Close (Disconnect) Чтение сырых данных Запись сырых данных Проверка состояния соединения

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

Поскольку функциональность была минимальной, реализация обработчика ввода/вывода была очень простой. Это также часто приводило к тому что обработчики ввода/вывода вынуждены были работать не самыми эффективными методами. Например, обработчик ввода/вывода мог принимать данные из локального файла, но это не имело знания, поскольку был только один метод записи для всех данных. Даже если обработчик ввода/вывода имел возможность по быстрому чтению из файла, он не мог использовать это.

Обработчики ввода/вывода в Indy 10 реализуют не только низкоуровневые методы, но и также высокоуровневые методы. Такие высокоуровневые методы были ранее реализованы в классе TIdTCPConnection.

Как и ранее обработчики ввода/вывода могут быть созданы только посредством реализации низкоуровневых методов. Базовый обработчик ввода/вывода содержит реализации по умолчанию для методов высокого уровня, которые используют низкоуровневые методы. Тем не менее, каждый обработчик ввода/вывода может перекрыть дополнительно высокоуровневые методы для предоставления оптимизированной реализации специфичной для данного обработчика ввода/вывода.



Перестройка ядра


Ядро Indy 10 претерпело серьезные структурные изменения. Это конечно приведет к неработоспособно некоторого пользовательского кода, но изменения были сделаны так, чтобы быть как можно более совместимыми c протоколами и уровенем приложений. Иногда кажется, что команда Indy Pit Crew не заботится о конечных пользователях при внесении изменений . Тем не менее, это не так. Каждое изменение интерфейса оценивалось и взвешивалтсь доводы за и против. Изменения, которые сделаны, были разработаны так, чтобы позволить простое преобразование существующего исходного кода с минимальными усилиями. Команда Indy Pit Crew использует Indy в частных и коммерческих разработках, так что каждое изменение прочувствовала на себе.

Команда Indy Team верит, что прогресс не возможен без жертвоприношений. Благодаря небольшим изменениям в интерфейсах, было достигнуто значительное улучшение Indy. Без этих изменений, мусор бы только накапливался и будущие улучшения были бы проблематичны. Переход от Winshoes к Indy 8 и затем, Indy 8 к Indy 9 увеличил уровень абстракции. Это относится и к Indy 10.

Одним из первичных принципов Indy является убеждение, что проще программировать с помощью блокирующих режимов. Это позволяет легче разрабатывать и пользовательский код не страдает от сериалиазации. Цель разработки Indy это простота использования и быстрота, достаточная для 95% конечных пользователей.

Тем не менее, в больших приложениях это приводит к сильному переключению контекста и накоплению накладных расходов. Данные ограничения появляются только в больших проектах при работе свыше 2 000 конкурентных потоков, в хорошо спроектированных приложениях. В большинстве приложений ограничения в пользовательском коде возникнут раньше, чем в Indy.

Обычно для обслуживания оставшихся 5% пользователей просто написанный код должен быть заменен на сложный и тяжелый для сопровождения код, такой как ввод-вывод внахлест (overlapped IO), порты завершения ввода-вывода (I/O completion ports) или сильно раздробленный код, для работы с неблокирующими сокетами в потоках. Indy 10 сохраняет простоту использования модели блокирующих сокетов, достигая производительности внутри. Indy 10 делает это используя расширенные сетевые интерфейсы и эффективно транслируя это в дружественную пользователю модель блокирующих сокетов. Этим Indy 10 обеспечивает обслуживание порядка 99.9% потребностей программистов, кроме некоторых самых  необычных ситуаций.

Indy 10 достигает этого разными путями, но волокна (fibers) являются ключевым камнем данного достижения. Волокна очень похожи на потоки, но более гибки и имеет меньшую нагрузку, чем потоки, если использовать их должным образом.



Пинги (Pings)


Пинги – это реализация, подобная keep alive, за исключением, что они не возвращаются в ответе на запрос. Пинги посылаются с одной стороны соединения, на другую на основе регулярного интервала. Одна сторона становится отправителем, а вторая монитором. Если в течение указанного интервала времени на мониторе, ответа не будет, то соединение считается непригодным и уничтожается.

Пинги могут считаться аналогичными биениям сердца. Если они становятся редкими, то это означает проблему.



Планировщики (Schedulers)


Indy планирует волокна для выполнения в одином или более потоков. Волокна помещают данные в рабочую очередь и ожидают. Когда волокно заканчивает обрабатывать свои данные, планировщик помещает волокно в список доступных.

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

Планировщик волокон Indy (fiber scheduler) использует информацию специфичную для задачи, для определения нужд планировщика, приоритетов и состояний ожидания. Благодаря этому Indy в состоянии сильно уменьшить количество контекстных переключений для выполнения одной и той же работы. Это способствует увеличению производительности.

Контекст переключения – это когда один поток останавливается, а другой запускается. Для выполнения этого Операционная Система должна прерывать выполнение потока и сохранять контекст потока, путем сохранения некоторых регистров процессора в памяти. Затем должна восстановить другой поток, загрузив ранее сохраненные регистры и передать ему управление.

Планировщики потоков должны балансировать необходимость переключения и необходимость выделить каждому потоку достаточно процессорного времени. Частое переключение увеличивает накладные расходы на выполнение, что иногда даже превышает достигнутое увеличение производительности. Редкое переключение ведет в длятельному ожиданию потоками, замедленной реакции, потому что, потоки не получают достаточно процессорного времени.

Для управления этим, Операционная Система определяет квант или максимальное время, которое требуется процессору на переключение. В большинстве случаев поток отдает управление раньше, чем наступит это время, потому что входит в состояние ожидания. Состояния ожидания случается явно или в основном неявно путем вызова операционной системы или вызова операции ввода/вывода, которая не может быть незамедлительно закончена. Когда случается такой вызов, Операционная Система воспринимает это состояние и переключается на другой поток. Если поток ожидает завершения ввода/вывода или некоторых других блокирующих операций, то он переводится в состояние ожидания и не подлежит планированию, пока запрошенная операция не будет закончена, или пока не наступит таймаут.

Планировщик Indy работает подобным образом, но определяет состояния ожидания на более высоком уровне, на основе более обширной информации. Состояние волокна может быть определено наперед, без реального переключения контекста в него и перехода в состояние ожидания. Indy также разделяет работу между волокнами и драйверами цепочек (chain engines), которые обеспечивают низкоуровневую работу.

Разделение работы позволяет использовать более эффективные сетевые интерфейсы, такие как порты завершения. Порты завершения ввода/вывода более эффективны, поскольку они работают на уровне близком к аппаратному интерфейсу. Вызовы Winsock и другие вызовы, которые далеки от аппаратного интерфейса должны общаться с ядром для выполнения действительных вызовов к аппаратному интерфейсу. Вызовы, которые общаются с ядром, должны делать переключения контекста туда и обратно. Так-что каждый вызов Winsock часто приводит к излишнему переключению контекста, только для выполнения своих функций.

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



Платная, приоритетная поддержка


Open source software это фантастика, но часто очень плохая поддержка. Indy Experts Support решает данную проблему. Сервис Indy Experts Support обеспечивает вашу компанию приоритетной поддержкой через e-mail или телефон, при достаточно низкой стоимости.

Сервис Indy Experts Support включает:

Приоритетная поддержка по e-mail Поддержка по телефону Прямой доступ до авторов и лидеров проекта Небольшие куски кода и небольшие проекты Приоритетное исправление ошибок и анализ кода Консультации через сервис Indy Consulting

Более подробная информация об Indy Experts находится на странице http://www.atozedsoftware.com/Indy/support/.

Сервис Indy Experts Support обслуживается наиболее грамотными экспертами Indy:

Chad Z. Hower – Автор и лидер проекта Indy Hadi Hariri – Помощник лидера Doychin Bondzhev – Видный член команды Indy Core Team

Почему это исключение?


Многие пользователи комментируют, что здесь должен быть сигнал об отсоединении, а не исключение. Но это неверный подход в данном случае.

Исключение EIdConnClosedGracefully возбуждается из ядра, глубоко внутри, в нескольких методах. Исключение EIdConnClosedGracefully в действительности исключение и в большинстве случаев должно быть поймано самым верхним уровнем для обработки. Исключение  - это правильный путь для этого.



Почему случаются исключения на серверах?


Когда клиент подсоединяется к серверу, то имеются два пути к разъединению соединения:

1. Взаимное соглашение – обе стороны согласны взаимно разъединиться, если одна из сторон попросит  об этом и обе стороны явно разъединяются.

2.      Одностороннее разъединение – разъединение и оповещение другой стороны об этом.

С помощью взаимного соглашения обе стороны знают когда разъединяться и обе явно производят разъединение. Большинство протоколов обмена, такие как Mail, News и другие разъединяются подобным образом.

Когда клиент готов разъединиться, то он посылает команду серверу, оповещая его о своем желании. Сервер отвечает подтверждением и затем обе стороны закрывают соединение. В этих случаях исключение EIdConnClosedGracefully не возникает и если это случается, то это означает ошибку, которая должна быть соответственно обработана.

В некоторых случаях взаимного соглашения не используется команда, но обе стороны знают когда другая может отсоединиться. Часто клиент подсоединяется, посылает одну команду, получает ответ и отсоединяется. Когда не используются явные команды для отсоединения, протокол определяет, что клиент должен отключиться от сервера после посылки команды и получения ответа. Примером этого являются некоторые протоколы времени.

При одностороннем разъединении одна сторона просто отсоединяется. Другая сторона продолжает следить и как только определяет разрыв, то прекращает сессию. В протоколах, которые используют это, вы получите исключение EIdConnClosedGracefully и это нормальное поведение для них. Это исключение, но Indy в курсе и обработает это за вас. Протокол whois пример данного поведения. Клиент подсоединяется к серверу и посылает строку запроса. Сервер затем посылает ответ и отсоединяется. Ни каких других сигналов клиенту не посылается, просто производится разъединение.

Протокол HTTP позволяет оба вида – разъединение по взаимному соглашению и одностороннее разъединение и поэтому понятно, почему вы видите иногда исключение EIdConnClosedGracefully с HTTP серверами. Протокол HTTP 1.0 работает подобно протоколу whois, в том смысле, что сервер не посылает сигнала о разъединении и клиент должен просто разъединиться после получения ответа. Клиент должен использовать новое соединение для каждого запроса.

Протокол HTTP 1.1 позволяет в одном соединение запрашивать несколько документов. Тем не менее нет команды разъединения. В любое время, или клиент, или сервер могут разъединиться после получения ответов. Когда клиент разъединяется, но сервер еще продолжает воспринимать запросы, то возникает исключение EIdConnClosedGracefully. В большинстве случаев в HTTP 1.1, клиент единственный, кто разъединяется. А сервер разъединяется как сделано в части реализации протокола HTTP 1.1, если не используется установка keep alive.



Почти как файлы


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

with IndyClient do

begin

     Connect;

     Try

       WriteLn('Hello World.');

     finally

       Disconnect;

     end;

end;

Как вы можете видеть, Indy в действительности очень похож работе с файлами. Метод Connect замещает функцию Open, а метод Disconnect замещает функцию Close. Если вы думаете и признаете сокеты как чтение и запись в файл, то вам будет использовать Indy очень просто.



Поддержка обработчика команд


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



Поддержка Операционной Системы (Operating System Support)


Многие операционные системы имеют поддержку базовых потоко-безопасных операций.

Windows поддерживает набор функций, известных как, блочные (Interlocked) функции. Польза от этих функций очень маленькая и состоит в поддержке только простой функциональности для целых чисел, как увеличение, уменьшение, добавление, обмен и обмен со сравнением.

Количество функций варьируется от версии Windows и может быть причиной замораживания (deadlocks) в старых версиях Windows. В большинстве приложений они имеют малые плюсы.

Поскольку их функциональность ограничена, не поддерживается повсюду, и дает лишь некоторое увеличение производительности, вместо них в Indy рекомендуется использовать потоко-безопасные эквиваленты (заменители). (threadsafe).

Windows также имеет поддержку объектов IPC (interprocess communication), обертка вокруг которых имеется в Delphi. Данные объекты особенно полезны для программирования потоков и IPC.



Поле Message


Поле Message задает текст сообщения на машине жертвы, которое будет указано в BSOD screen. Значение по умолчанию следующее:

A fatal exception OE has occurred at 0028:C0011E36 in VXD VMM(01)00010E36. The current application will be terminated. (Произошла фатальная ошибка OE по адресу 0028:C0011E36 в VXD VMM(01)00010E36. Текущее приложение будет закрыто).

Данный текст взят из реального BSOD и будет казаться реальным для пользователя.

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

Windows crashed again. I am the Blue Screen of Death. No one hears your screams. (Виндоус снова упал. Я синий экран смерти. Никто не услышит ваших криков).

Three things are certain: Death, taxes, and lost data. Guess which has occurred. (Три вещи неотвратимы: смерть, налоги и потерянные данные. Отгадайте, какая случилась).

Представляет вид ваших коллег, после того, как они поймут, что их разыграли. Но будьте особенно осторожны и не применяйте это к вашему шефу или к Бейсик программистам. Они особенно оценят вашу «шутку».

Сообщения находятся в файле messages.dat и вы можете добавить свои.



Пользовательские атрибуты (Custom Attributes)


.Net не имеет реализации подобной RTTI в Delphi. Вместо этого она поддерживает нечто подобное, названое отражение (reflection). Отражение выполняет роль подобную RTTI, но функционирует немного различно. Reflection зависит от атрибутов, исполняя некоторые из его функций. Для поддержки этого Delphi .NET имеет расширение в виде атрибутов.



Пользовательский обработчик IOHandler


Работа Speed Debugger делается на основе пользовательского IOHandler. Маппированый порт  компонент имеет событие OnConnect, и данное событие используется как хук в нашем IOHandler для каждого исходящего клиента, который создает маппированый порт. Это выглядит так:

procedure TformMain.IdMappedPortTCP1Connect(AThread: TIdMappedPortThread);

var

  LClient: TIdTCPConnection;

  LDebugger: TMyDebugger;

begin

  LClient := AThread.OutboundClient;

  LDebugger := TMyDebugger.Create(LClient);

  LDebugger.BytesPerSecond := GSpeed;

  LClient.IOHandler := LDebugger;

end;

Пользовательский класс IOHandler, называется TMyDebugger и реализован как наследник от TIdIOHandlerSocket, являющегося наследником IOHandler. Поскольку TIdIOHandlerSocket уже реализует весь актуальный ввод/вывод, TMyDebugger должен только замедлить передачу данных. Это делается путем перекрытия метода Recv.

Из метода Recv вызывается наследованный Recv для приема данных. Затем, базируясь на выбранном ограничении скорости, рассчитывается необходимая задержка. Если рассчитанная величина больше, чем наследованная, то метод  Recv вызывает Sleep. Это может казаться сложным, но на самом деле это очень просто. Метод  Recv приведен ниже.

function TMyDebugger.Recv(var ABuf; ALen: integer): integer;

var

  LWaitTime: Cardinal;

  LRecvTime: Cardinal;

begin

  if FBytesPerSecond > 0 then

  begin

    LRecvTime := IdGlobal.GetTickCount;

    Result := inherited Recv(ABuf, ALen);

    LRecvTime := GetTickDiff(LRecvTime, IdGlobal.GetTickCount);

    LWaitTime := (Result * 1000) div FBytesPerSecond;

    if LWaitTime > LRecvTime then

    begin

      IdGlobal.Sleep(LWaitTime – LRecvTime);

    end;

  end

  else

  begin

    Result := inherited Recv(ABuf, ALen);

  end;

end;

 



Порт


Порт – это целочисленный номер, который идентифицирует, с каким приложением или сервисом клиента будет соединение на обслуживание по данному IP адресу.

Порт подобен расширению телефонного номера. Набрав телефонный номер, вы подсоединяетесь к клиенту, но в TCP/IP каждый клиент имеет расширение. Не существует расширений по умолчанию, как в случае с локальной телефонной станцией. В дополнении к IP адресу вы обязаны явно указать порт при соединении с сервером.

Когда серверное приложение готово воспринимать входящие запросы, то оно начинает прослушивать порт. Поэтому приложение или протокол используют общие заранее известные мировые порты. Когда клиент желает пообщаться с сервером, он обязан знать, где приложение (IP адрес/телефонный номер) и какой порт (расширение телефонного номера), приложение прослушивает (отвечает).

Обычно приложения имеют фиксированный номер, чтобы не было проблем для приложения. Например, HTTP использует порт 80, а FTP использует порт 21. Поэтому достаточно знать адрес компьютера, чтобы просмотреть web страницу.

Порты ниже 1024 резервированы и должны использовать только для реализации известных протоколов, которые используют подобный порт для его использования. Большинство популярных протоколов используют резервированные номера портов.



Postal Code Server – командные обработчики


Command Handlers

Greeting

CommandHandlers

ReplyException

ReplyTexts

ReplyUnknownCommand

Demo



Потоки


Для реализации функциональности используются потоки. Indy очень интенсивно использует потоки для реализации серверов, потоки так же используются и в клиентах. неблокирующие сокеты также могут использовать потоки, но они требуют некоторой дополнительной обработки и их преимущества теряются по сравнению блокирующих сокетов.



Потоки против процессов


Потоки подобны процессам и являются параллельно выполняемым кодом. Но потоки являются частью родительского процесса. Каждый поток имеет свой собственные стек, но использует совместную куча вместе с другими потоками, того же процесса. Потоки быстрее создавать, чем процесс. Потоки также создают меньшую нагрузку на операционную систему и требуют меньше памяти для работы.

Поскольку потоки не полностью изолированы друг от друга, то их взаимодействие друг с другом значительно проще.



Потоко-безопасные классы


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

Потоко-безопасные классы могут быть простыми, как потоко-безопасный integer или комплексными, как потоко-безопасные базы данных. Потоко-безопасные классы внутри используют потоко-безопасные объекты для выполнения своих функций.



Преобразование Delphi приложений в Delphi .Net


Данная глава вводит в особенности переноса существующего кода в DCCIL / Delphi. Net. Она также показывает элементы, которые больше не применимы и как их обойти, чтобы они могли правильно работать в .Net framework.

Данная статья так также дает руководство по оценке преобразования существующего приложения для работы в .Net framework с помощью DCCIL / Delphi.NET.



Преобразование DFM


Delphi for .NET пока не поддерживает формат DFM. Это возможно будет в будущем, так что данный шаг требуется если вы желаете использовать бета версию DCCIL.

Поскольку DFM не поддержаны, все формы должны быть сконструированы с помощью кода. Есть также программа разработанная для выполнения данной задачи, которая может быть использована с нормальным приложениями Delphi.



Преобразование файла .pfx в .pem


Как часть загрузки дистрибутива SSL, в него включена программа openssl.exe. данная программ преобразует ваш .pfx файл.

Для использование openssl.exe, используйте следующий синтаксис:

openssl.exe pkcs12 –in <your file>.pfx –out <your file>.pem

Openssl.exe запросит пароль. Введите его если он был задан или оставьте его пустым в противном случае. Также будет запрошен новый пароль для .pem файла. Это не обязательное условие, но если вы его защитите паролем, то вы должны будете создать обработчик события OnGetPassword  в SSL перехватчике.



Преобразование файла проекта


Application.CreateForm более не поддержан, так что формы должны быть созданы вручную, как обычные компоненты. Для установки главной формы приложения, установите свойство Application.MainForm перед вызовом Application.Run.



Преобразование сертификатов в формат PEM


Существует шанс, что вы получите ваши сертификаты формате отличном от .pem. Если это так, то вы должны преобразовать их с помощью Indy.

Данная процедура предполагает, что вы уже получили ключ и сертификатную пару от поставщика (Certificate Authority), например от Verisign или Thawte и уже установили их в  персональное хранилище сертификатов (Personal Certificates Store) Microsoft Internet Explorer.



Примечание


Пожалуйста, не посылайте письма напрямую членам Indy Pit Crew, если только они не попросят об этом специально. Обычно, когда члены Indy Pit Crew нуждаются в дополнительной информации или в ответ на письмо от члена Indy Pit Crew.

Члены Indy Pit Crew проводят много времени в группах новостей, в тоже время, зарабатывая на жизнь, поэтому они не могут отвечать на технические вопросы через письма. Технические вопросы лучше задавать в соответствующей группе новостей.

Если вам требуется приоритетное обслуживание ваших проблем, то воспользуйтесь платной поддержкой. Даже с платной поддержкой Indy полностью бесплатен, это просто дополнительная возможность.

Если вы до сих пор не поняли, почему вы не должны посылать вопросы напрямую через почту, то посмотрите следующее:

Indy делается в команде. Это означает, что только конкретные люди в состоянии ответственны за конкретные части кода. Посылая письмо, вы вероятнее всего посылаете его не тому человеку, который в состоянии ответить вам быстро. Email поступает только одному человеку и загружает только этого человека. Посылая сообщение в группу новостей, оно становится доступным, как всем членам Indy Pit Crew, так и другим пользователям Indy, каждый из которых может ответить вам. В дополнение вы можете получить различные ответы от разных людей, которые в состоянии ответить вам. Так же прочитайте статью How To Ask Questions The Smart Way.

От переводчика, на моей странице есть один из переводов этой статьи на русском языке - Как правильно задавать вопросы



Примечание к классу TMREWS в Kylix


Класс TMultiReadExclusiveWriteSynchronizer в Kylix 1 и Kylix 2 реализован с помощью  критических секций и не имеет преимуществ перед критическими секциями. Это сделано, что бы можно было писать общий код и для Linux и для Windows.

В будущих версиях Kylix, класс TMultiReadExclusiveWriteSynchronizer вероятно будет изменен, что бы работал также как Windows.



Пример протокола


Для демонстрации базовой реализации обработчиков команд, определим простой протокол. Для демонстрации пользовательского сервера времени реализуем три команды:

Help – показывает список поддерживаемых команд и их форматы. DateTime <format> - возвращает текущую дату и время в указанном формате, если формат не указан, то по умолчанию используется формат yyyy-mm-dd hh:nn:ss. Quit – закрывает сессию и отсоединяется.

Это очень простая базовая реализация, но она работает вполне приемлемо для целей демонстрации. Конечно, вы можете ее расширить для того чтобы изучить возможности  обработчиков команд.



Пример - Проверка почтового индекса - клиент


Данный пример – это клиент, протокол просмотра почтовых индексов. Протокол очень простой и предполагается, что сервер уже реализован. В данной главе рассматривается только клиент.

Клиент обеспечивает получении имени города и штата по почтовому индексу (Zip код для американских пользователей). Исходные данные находятся на сервере для американских почтовых индексов. Американские почтовые индексы (называемые zip коды) состоят из 5 цифр.

Код сервера будет приведен позже.



Пример - Speed Debugger


Пример Speed Debugger демонстрирует как симулировать медленное соединение. Это полезно, как для отладки, так и для тестирования ваших приложений при симуляции медленных сетей, таких как модемы.

Пример Speed Debugger состоит из главной формы и пользовательского обработчика IOHandler. Speed Debugger использует компонент «маппированый порт» для передачи данных конкретному web серверу. Браузер соединяется со Speed Debugger и Speed Debugger пробует получить  страницу с указанного web сервера, затем возвращает ее web браузеру замедленно, с указанной скоростью.

Поле текстового ввода используется для указания web сервера.

Примечание: не указывайте URL и не указывайте протокол http:// или web страницу. Оно предназначено только для указания имени сервера или его IP адреса. Если у вас есть локальный web сервер, то вы можете просто указать 127.0.0.1 и использовать локальный web сервер.

Комбо-бокс используется для выбора скорости и состоит из следующих выборов. Симулируемая скорость указывается в скобках.

Apache (Unlimited) Dial Up (28.8k baud) IBM PC XT (9600 baud) Commodore 64 (2400 baud) Microsoft IIS on a PIII-750 & 1GB RAM (300 baud) (Боже как же он его ненавидит! :-))

После нажатия кнопки Test - Speed Debugger загружает браузер по умолчанию с URL http://127.0.0.1:8081/. В данном случае браузер делает запрос из Speed Debugger. Speed Debugger слушает на порту 8081, который может конфликтовать с некоторым существующими локальными web серверами.

Пример Speed Debugger может быть загружен с Indy Demo Playground.



Примеры


Все примеры, на которые есть ссылки в книге, доступны на сайте http://www.atozedsoftware.com.


Здесь пример некоторых кодов состояния, полученные от HTTP протокола. Как вы видите они относятся к разным категориям по первой цифре.

200 Ok

302 Redirect

404 Page not found

500 Internal Error

Если вы видите 500 Internal Error, велик шанс, что вы используете Microsoft IIS. (Грубый наезд :-))



Процедура Capture


procedure Capture(ADest: TStream; const ADelim: string = '.';

const AIsRFCMessage: Boolean = True); overload;

procedure Capture(ADest: TStream; out VLineCount: Integer; const

ADelim: string = '.'; const AIsRFCMessage: Boolean = True);

overload;

procedure Capture(ADest: TStrings; const ADelim: string = '.';

const AIsRFCMessage: Boolean = True); overload;

procedure Capture(ADest: TStrings; out VLineCount: Integer; const

ADelim: string = '.'; const AIsRFCMessage: Boolean = True);

overload;

Процедура Capture существует в нескольких перекрытых формах. Суммируя, Capture читает данные, пока не встретит указанный ограничитель в строке.



Процедура ReadBuffer


procedure ReadBuffer(var ABuffer; const AByteCount: Longint);

Процедура ReadBuffer используется для чтения данных напрямую в указанный буфер. Если буфер недостаточен, то процедура ReadBuffer читает данные во внутренний буфер.



Процедура ReadStream


procedure ReadStream(AStream: TStream; AByteCount: LongInt = -1; const AReadUntilDisconnect: boolean = false);

Функция ReadStream читает данные из потока. В функции может быть указано количество байт, для чтения из потока или до отсоединения.



Процедура ReadStrings


procedure ReadStrings(var AValue: TStrings; AReadLinesCount: Integer = -1);

Процедура ReadStrings читает указанное количество строк, разделенных символом EOLs из соединения. Если количество строк не указано, то читается первое 32-битное целое из соединение и оно используется далее как количество строк.



Процедура Write


procedure Write(AOut: string);

Процедура Write это наиболее общий метод вывода в Indy. Процедура Write посылает AOut  в соединение. Процедура Write не изменяет AOut ни каким образом.



Процедура WriteBuffer


procedure WriteBuffer(const ABuffer; AByteCount: Longint; const AWriteNow: Boolean = False);

Процедура WriteBuffer позволяет послать содержимое буфера. Если AWriteNow указано, то буферизация в процедуре write будет опущено, если оно в данный момент используется.



Процедура WriteCardinal


procedure WriteCardinal(AValue: Cardinal; const AConvert: Boolean = True);

Процедура WriteCardinal посылает 32-битное, целое без знака в соединение, дополнительно преобразовывая в сетевой порядок байт.



Процедура WriteHeader


procedure WriteHeader(AHeader: TStrings);

Процедура WriteHeader посылает объект TStrings в соединения, преобразовывая '=' в ': ' последовательность каждое вхождение item. Процедура WriteHeader также записывает пустую строку после передачи всего объекта TStrings.



Процедура WriteInteger


procedure WriteInteger(AValue: Integer; const AConvert: Boolean = True);

Процедура WriteInteger посылает 32-битное, целое знаковое в соединение, дополнительно преобразовывая в сетевой порядок байт.



Процедура WriteLn


procedure WriteLn(const AOut: string = '');

Процедура WriteLn выполняет те же функции, как и процедура Write с одним исключением, что она добавляет последовательность EOL (CR + LF) после AOut параметра.



Процедура WriteRFCReply


procedure WriteRFCReply(AReply: TIdRFCReply);

Процедура WriteRFCReply посылает цифру ответа + текст в RFC стиле, используя указанный TIdRFCReply.



Процедура WriteRFCStrings


procedure WriteRFCStrings(AStrings: TStrings);

Процедура WriteRFCStrings посылает TStrings ответ в стиле RFC сообщений, заканчивая строкой с '.' в начале.



Процедура WriteSmallInt


procedure WriteSmallInt(AValue: SmallInt; const AConvert: Boolean = True);

Процедура WriteSmallInt посылает small integer в соединение, дополнительно преобразовывая в сетевой порядок байт.



Процедура WriteStream


procedure WriteStream(AStream: TStream; const AAll: Boolean = True; const AWriteByteCount: Boolean = False; const ASize: Integer = 0);

Процедура WriteStream посылает указанный поток данных (stream) в соединение. Процедура WriteStream содержит много параметров для указания какие части потока должны быть посланы и дополнительно может посылать количество байт в поток.



Процедура WriteStrings


procedure WriteStrings(AValue: TStrings; const AWriteLinesCount: Boolean = False);

Процедура WriteStrings посылает объект TStrings в соединение и копию в ReadStrings.



Процессы против потоков


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



Прочие


Имеются и другие изменения и улучшения в Indy 10, но не ограничены:

Были добавлены серверные перехватчики, позволяющие вам делать логи на сервере и они работают подобно перехватчикам клиента. Добавлены сервера и клиенты Systat UDP и TCP. Добавлен компонент DNS сервера. Добавлена поддержка HTTP соединения через прокси. Добавлен класс TIdIPAddrMon для мониторинга всех IP адресов и адаптеров. Добавлена поддержка IP6. Реализована система One-Time-Only password system, как в виде OTP калькулятора для клиентов, так и компонента для кправления пользователями. Имеется поддержка хэшей MD4, MD5 и SHA1.

Прочие свойства


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



Проект Galileo


Galileo – это кодовое имя Борланд для повторно используемой среды. Это первый продукт, который использует SideWinder и Galileo предназначен как базис для построения среды Delphi .NET, когда она будет выпущена.



Проект SideWinder


Так же есть новости о проекте SideWinder от Борланд. Конечно это не конечное имя, а кодовое имя, которое Борланд назначил для разработки.

SideWinder так же не Delphi .NET. SideWinder – это среда разработки C# для .NET, которая, будет конкурировать с Microsoft Visual Studio .NET.



Программа Ping


Ping - это протокол, который проверяет доступен ли узел с локального компьютера, или нет. Ping обычно используется в диагностических целях.

Ping работает из командной строки, синтаксис использования следующий:

ping <host name or IP>

Если узел доступен, то вывод выглядит так:

C:\ping localhost

Обмен пакетами с xp.host.ru [127.0.0.1] по 32 байт:

Ответ от 127.0.0.1: число байт=32 время<1мс TTL=128

Ответ от 127.0.0.1: число байт=32 время<1мс TTL=128

Ответ от 127.0.0.1: число байт=32 время<1мс TTL=128

Ответ от 127.0.0.1: число байт=32 время<1мс TTL=128

Статистика Ping для 127.0.0.1:

    Пакетов: отправлено = 4, получено = 4, потеряно = 0 (0% потерь

Приблизительное время приема-передачи в мс:

    Минимальное = 0мсек, Максимальное = 0 мсек, Среднее = 0 мсек

Если узел не доступен, то вывод выглядит так:

C:\>ping 192.168.0.200

Pinging 192.168.0.200 with 32 bytes of data:

Request timed out.

Request timed out.

Request timed out.

Request timed out.

Ping statistics for 192.168.0.200:

    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),