Вчера мы рассмотрели небольшой пример того, как можно подключиться к FTP-серверу и скачать/загрузить файл. Однако сам по себе TFTPSend имеет ещё ряд отличий от уже известного нам класса THTTPSend (ну оно и понятно – протоколы-то разные). В частности, если Вы помните то, что я рассказывал про события в THTTPSend, то знаете, что все обработчики событий устанавливаются через его свойство Sock, которое дает доступ к объекту сокета.
В описании TFTPSend Вы можете обнаружить не только собственное событие OnStatus, которое отличается от уже известного нам, но также и сразу 2 свойства для доступа к двум разным сокетам – Sock и DSock.
У того, кто до этого момента не имел дел с работой FTP может возникнуть резонный вопрос: зачем два свойства, через которые можно определить идентичные события? И второй вопрос: когда следует использовать уже определенное в TFTPSend событие OnStatus.
Ответы на эти вопросы и будут рассмотрены в сегодняшнем посте.
Начнем, пожалуй с того, что отвечает нам на поставленные выше вопросы сама библиотека Synapse.
1. Событие OnStatus у TFTPSend.
type TFTPStatus = procedure(Sender: TObject; Response: Boolean;const Value: string) of object; TFTPSend = class(TSynaClient) ... property OnStatus: TFTPStatus read FOnStatus write FOnStatus; ... end;
Это событие используется для мониторинга запросов и ответов в процессе работы с FTP-сервером. Соответственно, если Response=True, то получен ответ сервера, иначе — запрос к серверу. Я написал следующий обработчик события OnStatus:
procedure TMainForm.FTPStatus(Sender: TObject; Response: Boolean; const Value: string); begin LogMemo.Lines.Add('Response: '+BoolToStr(Response,true)+' Value '+Value); end;
И после авторизации на сервере получил следующий лог:
Response: True Value 220 ProFTPD 1.3.3c Server ready. Response: False Value USER ********* Response: True Value 331 Password required for ****** Response: False Value PASS ********* Response: True Value 230 User intercas logged in Response: False Value TYPE I Response: True Value 200 Type set to I Response: False Value STRU F Response: True Value 200 Structure set to F Response: False Value MODE S Response: True Value 200 Mode set to S Response: False Value REST 0 Response: True Value 350 Restarting at 0. Send STORE or RETRIEVE to initiate ******* Response: False Value REST 1 Response: True Value 350 Restarting at 1. Send STORE or RETRIEVE to initiate ******* Response: False Value REST 0 Response: True Value 350 Restarting at 0. Send STORE or RETRIEVE to initiate ******* Response: False Value PWD Response: True Value 257 "/" is the current directory Response: False Value TYPE A Response: True Value 200 Type set to A Response: False Value EPSV 1 Response: True Value 229 Entering Extended Passive Mode (|||35082|) Response: False Value LIST / Response: True Value 150 Opening ASCII mode data connection for file list Response: True Value 226 Transfer complete
То есть, как видите, в логе представлено всё «общение» клиента и сервера — отправили команду, получили ответ и т.д. Событие OnStatus довольно удобная штука как раз для того, чтобы вывести лог «общения» клиента и сервера пользователю. Но как быть, если мы, например, качаем с сервера фильм? Каждый раз получать ответ в обработчике OnStatus и парсить в поисках чисел, а потом их складывать вместе? Согласитесь — не вариант. Смотрим далее, что нам говорит Synapse.
2. Свойства Sock и DSock TFTPSend
property Sock: TTCPBlockSocket read FSock;
Объект сокета, используемого для канала управления. Если Вы читали про FTP-протокол (вчера я в конце поста давал ссылку), то Вам должно быть понятно, что это за канал. Ну, а для тех, кто не читал — выписка из Вики:
Команды и данные, в отличие от большинства других протоколов, передаются по разным портам. Порт 20, открываемый на стороне сервера, используется для передачи данных, порт 21 для передачи команд. Порт для приема данных клиентом определяется в диалоге согласования.
И теперь смотрим, что говориться про DSock:
property DSock: TTCPBlockSocket read FDSock;
Объект сокета, используемого для канала передачи данных. И теперь остается только посмотреть работу с событиями этих сокетов в действии. Напишем следующие обработчики:
для Sock.OnStatus:
procedure MainForm.SockStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); begin SockLog.Lines.Add(GetEnumName(TypeInfo(THookSocketReason),ord(Reason))+' ='+Value); end;
для DSock.OnStatus:
procedure MainForm.DSockStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); begin DSockLog.Lines.Add(GetEnumName(TypeInfo(THookSocketReason),ord(Reason))+' ='+Value) end;
Теперь авторизуемся на сервере и попробуем скачать какой-нибудь файлик. Логи будут следующими: Для OnStatus TFTPSend:
Response: False Value EPSV 1 Response: True Value 229 Entering Extended Passive Mode (|||35156|) Response: False Value TYPE I Response: True Value 200 Type set to I Response: False Value RETR .clipboard.txt Response: True Value 150 Opening BINARY mode data connection for .clipboard.txt (25 bytes) Response: True Value 226 Transfer complete
Во второй строке лога — согласованый порт для передачи даннх. Если Вы попробуете скачать файл ещё раз — порт снова сменится. Для Sock.OnStatus (канал передачи команд:
HR_WriteCount =8 //отправили команду HR_CanRead = HR_ReadCount =48 //получили ответ (значение порта) HR_WriteCount =8 HR_CanRead = HR_ReadCount =19 HR_WriteCount =21 HR_CanRead = HR_ReadCount =71 HR_CanRead = HR_ReadCount =23
Как видите по Sock.OnStatus проходят только команды, что, собственно и было сказано ранее. И, наконец лог для DSock.OnStatus:
HR_ResolvingBegin =***.***.***.***:35156 HR_ResolvingEnd =***.***.***.***:35156 HR_SocketCreate =IPv4 HR_Connect =***.***.***.***:35156 HR_CanRead = HR_ReadCount =25 //прочитали данные файла HR_CanRead = HR_Error =10054,Connection reset by peer HR_SocketClose = HR_SocketClose =
Теперь нетрудно сопоставить все три лога и получить весь процесс работы клиента и сервера — в какой последовательности проходили команды, сколько траффика потрачено, сколько байт данных получено и т.д. И можно определиться с ответам на вопросы, которые поставлены в начале поста:
зачем два свойства, через которые можно определить идентичные события? Через обработчики событий объекта Sock можно организовать чтение сведений о передаваемых командах и полученных ответах сервера. Через обработчики событий DSock можно учитывать объем передаваемых/получаемых данных и организовать, например, скачивание больших файлов с ProgressBar’ом (как мы делали при работе с THTTPSend)
когда следует использовать уже определенное в TFTPSend событие OnStatus Обработчик на это событие логично ставить в том случае, если необходимо вывести лог общения сервера и клиента — наборы команд и ответов на них. То же самое можно сделать определив обработчики у объекта Sock, но событие OnStatus делает это за нас и, соответственно, избавляет нас от лишней рутины.
Книжная полка
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
|
||
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
А как организовать с прогресс баром можете дать пример.
тут описание всех событий. Там же и пример для THTTPSend — для TFTPSend прогресс вешается на то же событие
А как быт с докачкой файла если был сбой с сети он восстановится после подключения?
Влад! Куда ты пропал? Человек задал вопрос про докачку
Юра, ёклмн..забыл про вопрошающего. Бывает. Ну я все равно не в курсе как на FTP докачиваться — никогда с этим дела не имел. На HTTP всё просто — если сервер поддерживает докачку, то просто в следующем запросе отправить правильный заголовок Range в запросе и всё, а на FTP — не в курсе.
А если сервер перестал отвечать на команды? То есть возвращается пустое Value
Response: True Value
И? В чем суть вопроса? Ну перестал отвечать сервер — обработайте эту ситуацию как вам надо.
Вопрос — в чем может быть проблема? То есть пару раз сервер отвечает на запросы, а потом перестает:
Отвечает:
Response: False Value TYPE A
Response: True Value 200 Type set to A.
Перестает отвечать:
Response: False Value TYPE A
Response: True Value
Может кто сталкивался? Это же приложение с других компов (другая подсеть) с этим же ftp работает нормально