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

Вчера мы рассмотрели небольшой пример того, как можно подключиться к 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 и др.
купить книгу delphi на ЛитРес
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
8 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Xmen
Xmen
28/11/2011 12:48

А как организовать с прогресс баром можете дать пример.
 

Xmen
Xmen
15/12/2011 15:35

А как быт с докачкой файла если был сбой с сети он восстановится после подключения?

Юра
Юра
07/05/2012 17:18

Влад! Куда ты пропал? Человек задал вопрос про докачку

Дмитрий
Дмитрий
05/08/2014 20:08

А если сервер перестал отвечать на команды? То есть возвращается пустое Value
Response: True Value

Дмитрий
Дмитрий
06/08/2014 19:00
Ответить на  Vlad

Вопрос — в чем может быть проблема? То есть пару раз сервер отвечает на запросы, а потом перестает:
Отвечает:
Response: False Value TYPE A
Response: True Value 200 Type set to A.

Перестает отвечать:
Response: False Value TYPE A
Response: True Value

Может кто сталкивался? Это же приложение с других компов (другая подсеть) с этим же ftp работает нормально