Глубины Indy. 2. Техническая поддержка
Скачать 1.03 Mb.
|
8.1. Методы чтения 8.1.1. Функция AllData function AllData: string ; 34 Функция AllData блокирует и собирает все входящие данные, до разъединения соединения. Затем возвращает все собранные данные в качестве результата. AllData полезен для протоколов аналогичным WhoIs, после получения запроса, возвращает данные и сигнал, что соединение прекращено. AllData хранит свои буферы в оперативной памяти, поэтому не стоит использовать ее для больших по размеру данных. 8.1.2. Процедура 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 читает данные, пока не встретит указанный ограничитель в строке. 8.1.3. Функция CurrentReadBuffer function CurrentReadBuffer: string ; Функция CurrentReadBuffer возвращает все данные, которые находятся во внутреннем буфере Indy. Перед возвратом данных, CurrentReadBuffer также пытается прочитать все данные, которые она ожидает от подсоединенного сокета. Вызов CurrentReadBuffer очищает внутренний буфер. Если данных нет, то возвращается пустая строка. 8.1.4. Свойство InputBuffer property InputBuffer: TIdManagedBuffer read FInputBuffer; Свойство InputBuffer – это ссылка на экземпляр объекта TIdManagedBuffer. InputBuffer – это внутренний буфер Indy. TIdManagedBuffer имеет несколько расширенных буферов, но обычно пользователь не использует их. 8.1.5. Функция InputLn function InputLn(const AMask: String = '' ; AEcho: Boolean = True; ATabWidth: Integer = 8 ; AMaxLineLength: Integer = - 1 ): String ; Функция InputLn читает строку от сервере и возвращает е обратно reads a line from the server and echoes it back honoring the backspace character. Если параметр AMask указан, то строка AMask отсылается вместо каждого принятого символ. Функция InputLn полезна, когда вы не желаете отображать принятые символы, например пароль. 8.1.6. Процедура ReadBuffer 35 procedure ReadBuffer(var ABuffer; const AByteCount: Longint); Процедура ReadBuffer используется для чтения данных напрямую в указанный буфер. Если буфер недостаточен, то процедура ReadBuffer читает данные во внутренний буфер. 8.1.7. Функция ReadCardinal function ReadCardinal(const AConvert: boolean = true): Cardinal; Функция ReadCardinal читает 32-битное число без знака из соединения, с дополнительным учетом сетевого порядка байт. 8.1.8. Функция ReadFromStack function ReadFromStack(const ARaiseExceptionIfDisconnected: Boolean = True; ATimeout: Integer = IdTimeoutDefault; Функция ReadFromStack используется для заполнения внутреннего буфера Indy. Обычно конечные пользователи никогда не должны использовать эту функцию, поскольку она реализует новый метод чтения без использования текущих методов чтения, или когда они работают напрямую с внутренним буфером с помощью свойства InternalBuffer. 8.1.9. Функция ReadInteger function ReadInteger(const AConvert: boolean = true): Integer; Функция ReadInteger читает r 32-битное число со знаком из соединения, с дополнительным учетом сетевого порядка байт. 8.1.10. Функция ReadLn function ReadLn(ATerminator: string = LF; const ATimeout: Integer = IdTimeoutDefault; AMaxLineLength: Integer = - 1 ): string ; virtual ; Функция ReadLn читает данные из соединения, пока не встретит указанный ограничитель, в течение периода таймаута или в случае приема указанной максимальной длины строки. 8.1.11. Функция ReadLnWait function ReadLnWait(AFailCount: Integer = MaxInt): string ; Функция ReadLnWait подобна функции ReadLn с одним исключением, что она не возвращает результат, пока не примет, не пустую строку. Она также вернет количество принятых пустых строк. 8.1.12. Функция ReadSmallInt function ReadSmallInt(const AConvert: Boolean = true): SmallInt; Функция ReadSmallInt читает короткое целое из соединения, дополнительно делая подстройку под сетевой порядок байт. 36 8.1.13. Процедура ReadStream procedure ReadStream(AStream: TStream; AByteCount: LongInt = - 1 ; const AReadUntilDisconnect: boolean = false); Функция ReadStream читает данные из потока. В функции может быть указано количество байт, для чтения из потока или до отсоединения. 8.1.14. Функция ReadString function ReadString(const ABytes: Integer): string ; Функция ReadString читаетуказанное количество байт в строку и возвращает данные как результат. 8.1.15. Процедура ReadStrings procedure ReadStrings(var AValue: TStrings; AReadLinesCount: Integer = - 1 ); Процедура ReadStrings читает указанное количество строк, разделенных символом EOLs из соединения. Если количество строк не указано, то читается первое 32-битное целое из соединение и оно используется далее как количество строк. 8.1.16. Функция WaitFor function WaitFor(const AString: string ): string ; Функция WaitFor читает данные из соединения, пока не встретит указанную строку. 8.2. Таймауты чтения TIdTCPConnection (Все TCP клиенты и соединения, которые унаследованы от TIdTCPConnection) имеет свойство, названое ReadTimeout. Свойство ReadTimeout указывает таймаут в миллисекундах. Значением свойства по умолчанию является IdTimeoutInfinite. Данная установка запрещает таймауты. Таймаут не является таймаутом окончания работы. Это просто пустой таймаут. Что это значит, если указанная величина в свойстве ReadTimeout прошло и не данных для записи, то будет возбуждено исключение EIdReadTimeout. Многие сетевые соединения бывают очень медленные и данные не передавались, но соединение остается действительным. В такой ситуации, соединение может стать медленным и неприемлемым и будет только приводить к нагрузке сервера и малопригодным для клиента. Чтобы можно было оперировать такой ситуацией Indy реализует таймауты с помощью свойство ReadTimeout класса TIdTCPConnection. Свойство ReadTimeout по умолчанию равно нулю, которое запрещает обработку таймаутов. Для разрешения обработки таймаутов установите его значение в миллисекундах. Во время чтения, если в течение указанного интервала не будет приема данных из соединения, то возникнет исключение EIdReadTimeout. Таймаут не применяется если 37 принимаются данные в течение периода. Если вы запросили 100 байт и таймаут 1000 миллисекунд (1 секунда) операция чтения может занять более одной секунды. От переводчика: если в будет в течение каждой секунды принимать по одному байту, то в результате прием займет 100 секунд. Только если в течение одной секунды не будет принято ни одного байта, только тогда возникнет исключение EIdReadTimeout. 8.3. Методы записи 8.3.1. Функция SendCmd function SendCmd(const AOut: string ; const AResponse: SmallInt = - 1 ): SmallInt; overload ; function SendCmd(const AOut: string ; const AResponse: Array of SmallInt): SmallInt; overload ; Функция SendCmd используется для передачи текстовой команды и ожидает ответа в формате цифровых ответов RFC. 8.3.2. Процедура Write procedure Write (AOut: string ); Процедура Write это наиболее общий метод вывода в Indy. Процедура Write посылает AOut в соединение. Процедура Write не изменяет AOut ни каким образом. 8.3.3. Процедура WriteBuffer procedure WriteBuffer(const ABuffer; AByteCount: Longint; const AWriteNow: Boolean = False); Процедура WriteBuffer позволяет послать содержимое буфера. Если AWriteNow указано, то буферизация в процедуре write будет опущено, если оно в данный момент используется. 8.3.4. Процедура WriteCardinal procedure WriteCardinal(AValue: Cardinal; const AConvert: Boolean = True); Процедура WriteCardinal посылает 32-битное, целое без знака в соединение, дополнительно преобразовывая в сетевой порядок байт. 8.3.5. Процедура WriteHeader procedure WriteHeader(AHeader: TStrings); Процедура WriteHeader посылает объект TStrings в соединения, преобразовывая '=' в ': ' последовательность каждое вхождение item. Процедура WriteHeader также записывает пустую строку после передачи всего объекта TStrings. 38 8.3.6. Процедура WriteInteger procedure WriteInteger(AValue: Integer; const AConvert: Boolean = True); Процедура WriteInteger посылает 32-битное, целое знаковое в соединение, дополнительно преобразовывая в сетевой порядок байт. 8.3.7. Процедура WriteLn procedure WriteLn(const AOut: string = '' ); Процедура WriteLn выполняет те же функции, как и процедура Write с одним исключением, что она добавляет последовательность EOL (CR + LF) после AOut параметра. 8.3.8. Процедура WriteRFCReply procedure WriteRFCReply(AReply: TIdRFCReply); Процедура WriteRFCReply посылает цифру ответа + текст в RFC стиле, используя указанный TIdRFCReply. 8.3.9. Процедура WriteRFCStrings procedure WriteRFCStrings(AStrings: TStrings); Процедура WriteRFCStrings посылает TStrings ответ в стиле RFC сообщений, заканчивая строкой с '.' в начале. 8.3.10. Процедура WriteSmallInt procedure WriteSmallInt(AValue: SmallInt; const AConvert: Boolean = True); Процедура WriteSmallInt посылает small integer в соединение, дополнительно преобразовывая в сетевой порядок байт. 8.3.11. Процедура WriteStream procedure WriteStream(AStream: TStream; const AAll: Boolean = True; const AWriteByteCount: Boolean = False; const ASize: Integer = 0 ); Процедура WriteStream посылает указанный поток данных (stream) в соединение. Процедура WriteStream содержит много параметров для указания какие части потока должны быть посланы и дополнительно может посылать количество байт в поток. 8.3.12. Процедура WriteStrings procedure WriteStrings(AValue: TStrings; const AWriteLinesCount: Boolean = False); 39 Процедура WriteStrings посылает объект TStrings в соединение и копию в ReadStrings. 8.3.13. Функция WriteFile function WriteFile(AFile: String ; const AEnableTransferFile: Boolean = False): Cardinal; Функция WriteFile – это функция прямой посылки содержимого файла в соединение. Функция WriteFile использует операционную систему, просто используя TFileStream вместе с SendStream. 8.4. Буферизация записи TCP должен посылать данные пакетами. Размер пакетов может изменяться, но как правило он немногим менее 1 килобайта. Тем не менее, если TCP ожидает полного пакета данных, во многих случаях ответы могут быть не получены, поскольку запросы не были отосланы. TCP может использовать полные или неполные пакеты, Для неполных пакетов можно использовать алгоритм названый Nagle Coalescing. Nagle Coalescing внутренне буферизует данные, пока не будет достигнут указанный размер пакета или не истечет рассчитанное количество времени. Период времени обычно маленький и измеряется в миллисекундах. Посылка множества маленьких кусков данных может сделать алгоритм неэффективным, поскольку каждый пакет имеет служебный заголовок, что перегружает полосу пропускания и уменьшает скорость передачи данных. Данные могут буферизироваться в строку и быть посланы за раз, тем не менее это требует писать дополнительный код и исключает использование всех методов записи во время буферизации. Это также может усложнить ваш код и увеличить потребности в памяти. Вместо этого, вы можете использовать возможности Indy по буферизации записи. При использовании методов записи с буферизацией, вы можете позволить Indy буферизировать исходящие данные, что позволит вам использовать все возможные методы записи. Для начала буферизации записи, вызовите метод OpenWriteBuffer и укажите размер буфера. Затем вы можете вызывать все функции записи в Indy, и весь вывод будет буферизироваться, пока буфер не будет заполнен. Каждый раз когда будет достигнут размер буфера, буфер посылается в соединение и очищается. Если размер буфера не указан, все данные буферизуются и должны быть вручную отправлены. Имеется также несколько методов для управления буфером. ClearWriteBuffer очищает текущий буфер и сохраняет буфер открытым. FlushWriteBuffer сбрасывает текущее содержимое и также сохраняет буфер открытым. Для прекращения буферизации записи, вызовите CancelWriteBuffer или CloseWriteBuffer. CloseWriteBuffer записывает имеющие данные и заканчивает буферизацию записи, а CancelWriteBuffer закрывает буферизацию записи, без передачи. 8.5. Работа транзакций 40 Транзакции используются для определения единиц работы. Они называются рабочие транзакции и могут быть вложенными, и отделяют операции чтения и записи, которые могут быть одновременными. Рабочие транзакции обычно используются для отображения прогресса и состояния передачи. Транзакции определены в Indy различными, предопределенными методами, такими как TIdHTTP.Get, WriteStream и так далее. Как пользователь, вы также можете определить свои собственные транзакции, с помощью BeginWork, DoWork и EndWork. 8.5.1. События OnWork События OnWork состоят из трех событий и используется для связи состояний транзакций. Эти три события следующие: OnWorkBegin, OnWork и OnWorkEnd. При начале транзакции возникает событие OnWorkBegin. В событие OnWorkBegin передаются Sender, WorkMode и WorkCount. Параметр Sender это соединение, к которому относится транзакция. Параметр WorkMode указывает режим работы – читающая или пишущая транзакция. Транзакции Read и Write могут возникать одновременно и транзакции могут быть вложенными. Параметр WorkCount указывает размер транзакции. Во многих транзакциях, размер не может быть определен, и в этом случае, WorkCount имеет значение 0. Иначе, WorkCount показывает количество байт. Обычно данное событие используется для отображения начала процесса. Затем возникает серия событий OnWork. В событие OnWork передаются Sender, WorkMode и текущий WorkCount. Данное событие используется для отображения прогресса. Когда транзакция заканчивает, возникает событие OnWorkEnd. В событие OnWorkEnd OnWork передаются только Sender и WorkMode. Данное событие используется для отображения завергения процесса. 8.5.2. Управление своими собственными рабочими транзакциями Вы можете создавать свои собственные транзакции, вызывая BeginWork, DoWork и EndWork. Параметры те же самые, что описанны выше. Вызовы вложенных транзакций обслуживаются автоматически. Для выполнения транзакции, сначала вызовите BeginWork с указанием размера, если он известен. Затем вызовайте DoWork для отображения прогресса. По окончанию вызовите EndWork. 9. Обнаружение разъединения Поскольку Indy блокирующая по природе, и ее события используются только для обработки состояния, поэтому в ней нет событий оповещения о неожиданном разъединении соединения. Если вызов чтения или записи находится в состоянии исполнения и происходит неожиданный разрыв соединения, то вырабатывается исключение. Если же в этот момент нет вызова на чтение/запись, то исключение возникнет при первом вызове. 41 Имеется событие OnDisconnected, но это не то, о чем вы подумали. Событие OnDisconnected возникает при вызове метода Disconnect. Это событие никак не связано с неожиданным разъединением. 9.1. Скажем прощай В TCP протоколах, базирующихся на командах, самый простой путь завершить работу это сказать прощай (good bye). Эта команда распознается, только при наличии действующего соединении, но даже это большое удобство. Чтобы завершить работу, протоколы используют команду QUIT. Когда клиент готов завершить работу, вместо немедленного разъединения, сначала попробуйте послать команду QUIT на сервер. Затем подождите ответа и только после этого производите отсоединение сокета. Это хорошие манеры и позволяет обеим сторонам произвести правильное разъединение. Не делайте это как в телефонном разговоре, просто вешая трубку. Вы же не знаете, что произойдет в данном случае. Разница в том, что сервер может иметь сотни и тысячи клиентских соединений. Если они все отсоединятся без оповещения сервера, то сервер будет продолжать держать кучу мертвых соединений. 9.2. А нужно ли вам реально знать это? Многие программисты ошибаются, считая, что они должны немедленно узнать, что соединение неожиданно прервалось. Вы наверно слышали следующую сентенцию – «если дерево падает в лесу и никто при этом не присутствует, то кто услышит звук?». Если сокет отсоединяется, и он становится не доступным, то в действительно ли сокет закрывается? В большинстве случаев ответ НЕТ. Если сокет физически отсоединен и недоступен, то исключение не будет возбуждено, до тех пор, пока не будет произведена попытка доступа к сокету. Это может казаться странным, но это также как при работе с файлами. Представим себе, что вы открыли таблицу Экселя с гибкого диска, и затем вынули диск из дисковода. Вы можете продолжать работать с файлом, потому что он кэширован в памяти и Эксель, в данный момент, не обращается к физическому файлу. Иногда в течение этого времени вы забываете, что вы вынули дискету из дисководу. Позже вы продолжаете работу с вашей таблицей, все прекрасно пока вы не захотите сохранить ваши изменения. Только в этот момент вы получите сообщение об ошибке. Эксель не получает "EAnIdiotRemovedTheFloppyDiskException", когда вы вынули дискету, но он имеет открытый файл на этом диске. |