20.01.2015 Views

ИюНь - Xakep Online

ИюНь - Xakep Online

ИюНь - Xakep Online

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!