You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
coding<br />
По нажатию на кнопку «Настройки» будет вызываться дополнительная<br />
форма, в которой нужно будет ввести имя пользователя, пароль, сервер<br />
и порт.<br />
Кодинг<br />
Простенький дизайн нашего FTP-клиента готов, поэтому приступаем к<br />
приготовлению горячей начинки — написанию кода. Первым делом не<br />
забудь подключить к нашему проекту модуль Winsock.pas, иначе вызов<br />
сетевых функций будет невозможен. Теперь надо объявить все необходимые<br />
переменные в разделе private:<br />
_wsaData:TWSADATA;<br />
_clientSocket:TSocket;<br />
_serverSocket:TSocket;<br />
_clientAddr:sockaddr_in;<br />
_serverAddr:sockaddr_in;<br />
_mode:integer;<br />
_tempSocket:TSocket;<br />
Об их предназначении ты узнаешь по ходу рассмотрения примера. При<br />
описании сетевых функций я говорил, что перед их использованием<br />
нужно инициализировать сетевую библиотеку. Инициализацию сетевой<br />
библиотеки я делаю во время создания формы, а ее освобождение<br />
— во время закрытия окна. Если при этом у тебя возникли проблемы,<br />
то открывай исходник на нашем DVD и сравнивай. После инициализации<br />
сетевой библиотеки можно попытаться соединиться с удаленным<br />
сервером. По нажатию кнопки «Соединиться» у меня вызывается<br />
самописная процедура _connect(), которой нужно передать все необходимые<br />
для подключения данные (адрес сервера, логин, пароль,<br />
порт). Код этой процедуры ты можешь увидеть во врезке «Соединяемся<br />
с сервером».<br />
Давай-ка подробно рассмотрим содержимое кода установки соединения<br />
с удаленным сервером, отображенного в этой врезке. В самом<br />
начале я создаю новый сокет. Ты уже знаешь, для того чтобы создать<br />
новый сокет, нужно воспользоваться функцией SOCKET, которая после<br />
выполнения возвратит указатель на созданный сокет. После вызова<br />
функции SOCKET, я проверяю, а не возникла ли ошибка. Если да, то<br />
я запускаю самописную процедуру GetError, передав ей название<br />
вызываемой функции. Процедура GetError попытается получить код<br />
ошибки и в конце концов проинформирует пользователя, напечатав в<br />
TRichEdit соответствующий текст. Код процедуры GetError ты можешь<br />
посмотреть, открыв исходник примера, любезно дожидающийся тебя<br />
на нашем диске. Если ошибки не возникло, то можно начинать готовиться<br />
к соединению с удаленным сервером. Как ты должен помнить,<br />
чтобы установить соединение с сервером, нужно вызвать функцию<br />
connect, которой необходимо передать структуру типа sockaddr_in.<br />
Ну а чтобы ее передать, ее нужно заполнить, что я и делаю. После<br />
заполнения структуры, я вызываю функцию WSAAsyncSelect(). Эта<br />
функция устанавливает асинхронный режим для выбранного сокета и<br />
заставляет Windows генерировать сообщения для сетевых событий.<br />
Таким образом, нам достаточно указать сообщение, которое должно<br />
приходить окну нашего приложения при возникновении события на<br />
определенном сокете.<br />
На первый взгляд может показаться, что этот метод сложен в реализации.<br />
На самом деле это не так, и через несколько минут ты в этом убедишься, но<br />
сначала давай взглянем на параметры, которые нужно передать функции:<br />
1) s — сокет, за событиями которого необходимо наблюдать; 2) hWindow<br />
— окно, которое будет принимать сообщения; 3) wMsg — системное<br />
xàêåð 06 /102/ 07<br />
/<br />
событие, которое нужно генерировать; 4) lEvent — сетевые события, за<br />
которыми мы будем наблюдать. В качестве событий ты можешь указать:<br />
FD_READ (возникает, когда пришли данные), FD_WRITE (проявляется,<br />
когда можно передавать данные), FD_OOB (когда прибыли срочные данные),<br />
FD_ACCEPT (когда в очереди сокета есть новое подключение), FD_<br />
CONNECT (при соединении с сервером). В качестве третьего параметра я<br />
указал лишь FD_READ. Когда на наш сокет придут данные, главное окно<br />
нашего приложения получит сообщение WM_MYSOCKMESS. Чтобы его не<br />
прозевать, нам нужно написать процедуру, которая будет перехватывать<br />
нужное сообщение.<br />
Перед тем как привести код процедуры, я хотел бы объяснить тебе, что<br />
собой представляет WM_MYSOCKMESS. В нашем примере это константа,<br />
которая объявлена мной и равна WM_USER+1. Что такое WM_USER Это<br />
число. Все числа, меньше этого, могут уже использоваться системой,<br />
поэтому, чтобы не было конфликтов, нужно просто использовать это<br />
число +1.<br />
Немного отвлечемся от рассмотрения функции WSAAsyncSelect() и<br />
вернемся к разбору кода установки соединения с удаленным сервером.<br />
После WSAAsyncSelect() вызывается функция Connect, которая начинает<br />
устанавливать соединение с удаленным сервером. По окончанию выполнения<br />
функции Connect я приступаю к отправке данных для прохождения<br />
авторизации (вспоминай теорию). Отправка данных реализована в самописной<br />
функции _send(). В качестве параметров ей нужно передать сокет,<br />
через который будут отправлены данные, и сами данные.<br />
Теперь вернемся к интересной функции WSAAsyncSelect(). Я уже говорил,<br />
что для перехвата нужного события необходимо объявить специальную<br />
процедуру. В примере я объявил ее в разделе private следующим образом:<br />
procedure NetMSG (var M:TMessage); message WM_<br />
MYSOCKMESS;<br />
Код тела процедуры ты можешь увидеть в примере на диске. Как видно<br />
из описания, в процедуру передается структура типа TMessage. В этой<br />
структуре имеется несколько параметров, но нас будут интересовать<br />
только два: WParam и LParam. В первом хранится дескриптор сокета, на<br />
котором произошло событие, а во втором — его тип. Для проверки типа я<br />
использую управляющую структуру CASE, в которой и проверяю интересующие<br />
меня события.<br />
При возникновении события FD_READ вызывается процедура _recv, которая<br />
и выполняет чтение данных с определенного сокета. Код процедур _recv<br />
и _send (для отправки данных) ты можешь увидеть в исходнике примера.<br />
Тестирование<br />
Наш пример наполовину готов, теперь самое время протестировать его<br />
работоспособность. Попробуем скомпилить наше приложение и подцепиться<br />
к какому-нибудь ftp-серверу. Результаты моего тестирования ты<br />
можешь увидеть на рисунке. Для теста я подцепился к серверу своего<br />
хостера и успешно прошел авторизацию.<br />
Disconnect<br />
Рассмотреть весь код FTP-клиента в рамках одной статьи просто невозможно.<br />
Поэтому разбираться с установлением второго соединения (для<br />
передачи данных) тебе придется самостоятельно. Сильно по этому поводу<br />
не переживай. Ты всегда можешь заглянуть на наш диск и посмотреть<br />
исходник FTP-клиента, в котором я уже реализовал получения списка<br />
файлов определенной директории. Весь исходник я постарался максимально<br />
прокомментировать, поэтому с пониманием возникнуть проблем<br />
не должно. z<br />
113