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

Этот пост можно считать как небольшое примечание к книге по Synapse. Потребность в этом примечании возникла по нескольким причинам.

Во-первых, при переходе с Indy на Synapse у разработчиков часто возникают вопросы именно в части того, как Synapse использует различные таймауты, а именно — как установить таймаут на соединение, чтение/запись данных, почему не срабатывает таймаут и т.д. Достаточно забить в поиск фразу «таймаут synapse» и посмотреть различные обсуждения на форумах.

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

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

Версия Synapse и версии модулей Synapse

На момент написания этой статьи самой актуальной стабильной версией Synapse была Synapse release no. 40. Актуальная версия библиотеки выкладывается на этой странице официального сайта  в виде обычного zip-архива, содержащего все модули библиотеки.

Итак, с версией библиотеки разобрались — это двухзначное число (пока двухзначное), которое можно увидеть на странице загрузок

synapse_release

Помимо архива со стабильной версией нам также предоставляется возможность получать самые свежие исходники Synapse из репозитория на SourceForge. О том, как скачивать исходники из SVN можно узнать из двух статей, опубликованных в блоге ранее:

  1. Совместная работа над проектом. Работа в проектах на Code.Google. Здесь рассказывается о настройке TortoiseSVN

  2. Subversion в Delphi XE. Впечатления после одного дня работы. Здесь вы узнаете как использовать встроенный в Delphi клиент для SVN (сам я встроенным клиентом не пользуюсь, поэтому не могу сказать как сильно изменилась его работа в Delphi XE6 и других версиях Delphi после XE)

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

Скачивая исходники из репозитория вы получаете новые версии модулей Synapse. Версия модуля указывается в исходном коде самой первой строке. Ниже, на рисунке показана версия модуля blcksock.pas:

synapse_release_module

В итоге такой нумерации модулей и библиотеки в целом может возникнуть такая ситуация, как у меня недавно: версия библиотеки одинаковая — 40, но версии модуля по которому возник вопрос — разные, т.к.  разработчик скачал архив с последней версией библиотеки и работает с ней, а я качаю исходники из ветки trunk репозитория. Итог: я даю решение проблемы, которое у меня прекрасно работает, но у другого человека — ошибка, говорящая о том, что свойство класса не определено. И оба при этом правы :) Проблему мы, конечно, успешно решили, но из-за путаницы в версиях модулей, затратили на решение проблемы непозволительно больше времени, чем требовалось.

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

Всё, что будет сказано ниже относится к версии 009.009.001 модуля blcksock.pas

Работа с тайм-аутами в Synapse

В Synapse у сокета (класс TBlockSocket) можно определить следующие тайм-ауты:

1. Тайм-аут для операций записи. Этот тайм-аут устанавливается вызовом метода

procedure SetSendTimeout(Timeout: Integer);

2. Тайм-аут для операций чтения. Устанавливается вызовом метода

procedure SetRecvTimeout(Timeout: Integer);

Если значения обеих этих тайм-аутов вы хотите установить одинаковыми, то достаточно вызвать третий метод:

procedure SetTimeout(Timeout: Integer);

3. Тайм-аут соединения. Этот тайм-аут устанавливается через свойство:

property ConnectionTimeout: Integer read FConnectionTimeout write FConnectionTimeout;

Все значения тайм-аутов устанавливаются в миллисекундах. Например, чтобы установить все три тайм-аута в значение 3 секунды, то достаточно написать:

var Sock: TBlockSocket;
begin
  Sock.SetTimeout(3000);
  Sock.ConnectionTimeout:=3000;
end;

Кроме этого, для работы с тайм-аутом на чтение в Synapse у сокета имеется такое свойство:

property InterPacketTimeout: Boolean read FInterPacketTimeout Write FInterPacketTimeout;

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

После того, как мы указали значение какого-либо тайм-аута Synapse вызывает исключение в том случае, если время затраченное на операцию будет превышать установленное значение. То есть, если мы указываем Connection Timeout равным 5000 мс, то исключение будет вызвано, если время прошедшее с начала соединения будет равно или больше 5001 мс.

Теперь рассмотрим пример использования тайм-аутов в Synapse.

Проверка на соединение — это, наверное, самый популярный вопрос, касающийся Synapse — как проверить, что соединение прошло успешно и при этом затратить на проверку определенное время?

Например, мы хотим проверить, что какой-либо хост жив и считаем, что если на соединение затрачено больше 5 секунд, то хост «умер».

Для решения этой задачи нам идеально подходит тайм-аут соединения (ConnectionTimeout). Напишем такую функцию:

function Tfmain.CheckHost(const AIP, APort: string; ATimeOut: integer; out AConnected:boolean): single;
var ASock: TTCPBlockSocket;
    iCounterPerSec: TLargeInteger;
    T1, T2: TLargeInteger;
begin
  ASock:=TTCPBlockSocket.Create;
  try
    ASock.ConnectionTimeout:=ATimeOut;
    //засекаем время
    QueryPerformanceFrequency(iCounterPerSec);
    QueryPerformanceCounter(T1);
    //пробуем соединиться
    ASock.Connect(AIP,APort);
    QueryPerformanceCounter(T2);
    Result:=(T2-T1)/iCounterPerSec;//определяем сколько секунд было затрачено
    AConnected:=ASock.LastError=0;
    ASock.CloseSocket;//закрываем сокет.
  finally
    ASock.Free;
  end;
end;

Теперь, чтобы проверить соединение и определить за какое время оно было установлено достаточно вызвать эту функцию так:

var TimeElapsed: single;
    Connected: boolean;
begin
   TimeElapsed:=CheckHost('127.0.0.1','80',5000,Connected);
   if Connected then
     ShowMessage('Соединение прошло успешно. Затрачено '+FormatFloat('0.0000', TimeElapsed)+' сек.')
   else
     ShowMessage('Ошибка соединения. Затрачено '+FormatFloat('0.0000', TimeElapsed)+' сек.')
end;

После того, как соединение произведено, мы можем начинать читать/записывать данные и здесь используются тайм-ауты чтения/записи. Их значения мы можем устанавливать и использовать, например, чтобы закрывать «медленные» соединения, которые не будут отвечать нам заданным критериям. Например, выполнив такой код:

Sock.SetRecvTimeout(1000);
Sock.RaiseExcept:=True;

Мы будем получать исключение от Synapse, если очередной пакет данных (или очередная операция чтения) заняла более 1 секунды.

Вот, собственно, все примечания, которые я пока готов внести в книгу по Synapse. В заключение в очередной раз прошу: если у вас есть какие-либо дополнения или исправления по приведенной выше информации, то сообщите мне в комментариях к этой статье или на email: admin @ webdelphi.ru (пробелы убрать). Буду благодарен за ценные замечания, дополнения, новые примеры по теме.

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
3 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Михаил
Михаил
31/07/2014 09:15

В скачанной версии release no. 40. версия модуля blcksock.pas 009.008.005, откуда Вы взяли 009.009.001 ???

skyfarrier
skyfarrier
02/08/2014 20:12

> InterPacketTimeout
Неплохо было бы чуть подробнее пояснить про этот параметр. Сам его ни разу не использовал, но документация указывает на его довольно таки неслабую «хитрость». :)