|
|
|
||||||||||||
|
|
Собственный, легко управляемый и профессионально разработанный сайт – необходимый элемент любого бизнеса. Находитесь ли Вы в командировке, в дороге, дома или на отдыхе имея компьютер, подключенный к сети Internet, Вы получаете доступ к управлению Вашим сайтом! |
|||
Почтовая программа на Java - своими руками!Статьи → Программирование на JavaПередача данных
Класс POPException Команды протокола РОРЗ Листинг 1 -------------------------------------------------------------------------------- Написание программ на Java представляет собой весьма интересное занятие, поскольку можно абстрагироваться от многих деталей, с которыми неизбежно сталкиваются пользователи Cи++, Паскаля и других языков программирования третьего поколения. С самого начала специалисты корпорации Sun задумали Java как язык, стирающий разницу между разрозненными компьютерами и сетями, и, видимо, поэтому значительная часть библиотеки классов Java абстрагирует сетевые операции и транспортные протоколы. Простейшая Java-программа, принимающая почту с сервера, - это по силам каждому. Передача данных Прежде чем написать почтовый клиент, неплохо было бы изучить язык, на котором общаются почтовый клиент и сервер, - протокол POP3 (Post Office Protocol). Именно с помощью этого протокола в большинстве случаев принимаются почтовые сообщения такими популярными почтовыми программами, как Microsoft Outlook и Express Netscape Messanger. Для начала примите к сведению, что все почтовые операции на нижнем уровне производятся с применением транспортного протокола TCP. Сокет сервера передает данные в формате POP3 TCP-пакетами в порт 110 (более ранняя вторая версия протокола POP использовала порт 109). Кроме того, необходимо знать, что команды от клиента к серверу пересылаются в виде текстовых строк, завершающихся парой символов "перевод каретки" (CR) и "перевод строки" (LF). Получив такое сообщение, почтовый сервер приступает к тяжелой работе: либо отвечает на ваши команды, либо пересылает сообщения, имеющиеся в вашем почтовом ящике. Вот здесь начинается настоящее мучение, ибо те, кто разрабатывал протокол POP3, променяли удобство использования на простоту реализации, не подумав о программистах, которым с ним работать. Формат обмена данными Команды, которые вы отправляете серверу, делятся на две категории: без параметров и содержащие параметры. Если простые команды без параметров состоят всего из одного слова, то в команды с параметрами добавляются текстовые параметры (или цифровые параметры, преобразованные в текстовую форму и разделенные пробелами). Каждый параметр может иметь длину до 40 символов. В качестве примера простой команды можно привести команду "STAT", которая запрашивает состояние вашего почтового ящика. Примером команды с параметром может служить команда "USER Mitrich", сообщающая серверу, что к нему подключается пользователь с именем Mitrich. Прежде чем отправиться дальше, загляните в таблицу и ознакомьтесь со всеми командами, которые описывает протокол POP3. Возвращаемые сообщения могут быть двух видов: одно- и многострочные. В первом случае сервер возвращает одну строку; она начинается с признака статуса +OK или -ERR, говорящих об успехе или неудаче выполнения последней команды. Следом за признаком статуса сервер передает полезную информацию различного назначения. Завершается строка символами '\r' и '\n'. Если же возвращаемое сообщение многострочное, то оно передается строка за строкой, каждая из которых завершается '\r' и '\n', а в качестве признака окончания передачи используется строка из единственного символа '.' (точка), также оканчивающаяся символами возврата каретки и перевода строки. Класс POPClient Ядро почтового клиента - это класс POPClient, реализованный на языке Java (см. листинг 1). Он предоставляет пользователю несколько полезных функций для управления посылкой команд серверу и получения ответа от последнего. Класс POPClient вмещает в себя два внутренних класса - POPCommand и POPResponse. Такого разбиения единого, казалось бы, класса на подклассы требует сама суть объектно-ориентированного программирования: каждая сущность должна быть реализована как отдельный класс. А поскольку и POPCommand и POPResponse являются вспомогательными по отношению к главному классу POPClient, то они выполнены не как независимые классы, а как классы внутренние. Средства пакета JDK 1.1 предусматривают решение подобных задач. Внутренний класс POPCommand Класс POPCommand, как вы, наверное, уже догадались, является инкапсуляцией команды протокола POP3. Для его создания нет конструктора, поэтому этим занимается компилятор Java. С помощью объектов этого класса формируются команды для посылки серверу и производится собственно посылка команды. Кроме того, обязанностью этого класса является чтение ответа сервера на посланную ранее команду. Самую черную работу на нижнем уровне выполняют следующие методы:
Нетрудно догадаться, что это всего лишь оболочки для посылки команд с аналогичными именами. Внутри этих методов происходит стандартная обработка: имеющийся аргумент проверяется, передается вспомогательному методу transactCommand() и затем возвращается в виде true (команда прошла и обработана сервером) или false (произошла ошибка). Когда же сервер прислал вместо вразумительного ответа "тарабарщину", происходит возбуждение исключения под названием POPException (о нем ниже в разделе "Класс Метод transactCommand принимает текстовую строку, которая соответствует посылаемой команде, передает ее методу sendCommand(), затем читает ответ сервера с помощью метода readCommandResponse(). В заключение вызывается метод isSucceed() внутреннего класса POPResponse. Этот метод возвращает результат последней транзакции. Если работа sendCommand() достаточно понятна, то работа метода readCommandResponse() требует некоторого пояснения. В начале своей работы этот метод создает объект класса StringBuffer для временного хранения данных. Потом из потока ввода, подключенного к сокету, командой ir.readLine() читается строка ответа, которая добавляется к буферу строки методом append(). В момент окончания работы метода значение буфера преобразуется в строку методом toString() и записывается во внутреннее хранилище класса POPResponse методом Но не все так просто, как может показаться с самого начала. Дело в том, что читать данные из потока сокета можно, а вот установить момент, когда они считаны до конца, нельзя. И документация в этом деле, увы, ничем не поможет. Там рекомендовано читать строки из сокета до тех пор, пока возвращаемое значение не будет равно null. Но уверяю вас, этого момента вы не дождетесь. Точно так же вы не сможете воспользоваться методом read() для чтения из-за того, что и он блокируется при достижении конца передачи данных. Со стороны это выглядит как зависание, но на самом деле поток, в котором вызывается метод чтения данных, просто переходит в состояние ожидания очередной порции информации. Поэтому мы идем на компромисс и в дополнение к методу readCommandResponse() реализуем метод readMessage(), который предназначается лишь для считывания многострочного почтового сообщения. Конец передачи данных мы определяем по строке, состоящей из одного символа точки ".". Метод readMessage() вызывается из командного метода retr() и, вместо того чтобы, как другие команды, сделать вызов метода transactCommand(), выполняет следующие три строки на sendCommand("RETR " + Integer.toString(number)); Внутренний класс POPResponse Следующий внутренний класс POPResponse отвечает за хранение полученных от сервера данных и предоставление удобного интерфейса для их обработки. Все данные, принятые от сервера, сохраняются методом setBuff() в переменной buff, которая есть не что иное, как ссылка на строку класса String. Для вспомогательных нужд есть метод getBuff, с помощью которого можно получить содержимое хранилища в том виде, в каком оно было получено от почтового сервера. Для предварительной обработки данных вы можете вызывать еще два полезных метода: cutOffStatus() и getServerComment(). Первый из них берет содержимое временного хранилища, отрезает от него признак статуса (+OK или -ERR) и возвращает оставшуюся строку. Второй метод возвращает текстовое сообщение, которое было передано POP-сервером сразу за признаком статуса. Следует, однако, отметить, что применять этот метод можно лишь после того, как серверу была передана команда, следом за которой сервер непременно пришлет сообщение (см. таблицу), иначе возвращенная методом getServerComment() строка будет бессмысленна. Настал черед главного класса POPClient, с которым нам нужно разобраться. Сразу после объявления его самого описывается странная на первый взгляд переменная debug. Значение этой переменной управляет включением и выключением вывода отладочных сообщений в поток System.out. Если установить значение true, то специально написанный метод logText() будет посылать любую текстовую строку, которую вы ему передадите в окно консоли. После окончания отладки класса, вы можете установить debug в состояние false, и ваши строки, передаваемые logText(), уже не будут выводиться. Мало того, компилятор автоматически уберет посылки текста в окно консоли, оптимизируя код. Данная возможность походит на директивы условной компиляции препроцессора языков Cи и Cи++. О другой функции метода logText() мы поговорим чуть позже. В начале класса POPClient объявляется несколько полей, имеющих следующее назначение:
В конструкторе по умолчанию производится создание новых экземпляров объектов внутренних классов POPCommand и POPResponse для дальнейшей работы. Если вам требуется протоколировать работу вашего почтового клиента, то воспользуйтесь другим конструктором, принимающим имя файла, который будет служить файлом протокола. Сначала этот конструктор вызовет конструктор по умолчанию, инициализируя таким образом внутренние классы, а затем создаст поток вывода данных в файл. Если таковой поток не удается создать, то возникает исключение ввода-вывода, которое мы перехватываем, и устанавливаем флаг разрешения протокола в положение "отключено" Для забывчивых программистов в классе предусмотрен финализатор - метод finalize(), вызываемый сборщиком мусора в момент завершения работы класса. Финализатор вызывает метод disconnect(), отключающий клиента от почтового сервера, если программист по каким-либо причинам не вызывал метод Для соединения с POP-сервером создаваемый нами класс оснащен методом connect(), который достаточно прост. На первом этапе connect() создает сокет для присоединения к серверу с заданным именем и портом. Если сервер с именем hostName не существует, то после некоторого ожидания будет возбуждено исключение UnknownHostException. То же произойдет при возникновении проблем с вводом-выводом данных - будет сгенерировано исключение IOException. Мы перехватываем эти исключения и генерируем свое - POPException. В качестве параметра конструктора задается константа, определяющая вид исключения, которое мы хотим возбудить. После создания сокета, мы вызываем его методы getInputStream()и getOutputStream(), чтобы получить ссылки на потоки ввода и вывода сокета, через которые мы будем посылать и получать данные. Для удобства работы полученные ссылки преобразуются в экземпляры объектов классов BufferedReader и PrintWriter, пришедших на смену морально устаревшим классам потоков BufferedInputStream и PrintStream. Остается считать ответ сервера: command.readCommandResponse(); return response.isSucceed(); Метод logText(), который косвенно упоминался выше, служит для выполнения двух функций: запись строки, полученной через параметр text, в файл протокола, если протоколирование разрешено. Эти же данные пересылаются в окно консоли в том случае, если флаг debug задан как Для получения доступа к почте необходимо вызвать метод login(), посылающий имя пользователя и пароль почтовому серверу. Если какой-либо из параметров неверен, то происходит генерация исключения Еще два метода deleteMessage() и undoDeletes() служат для удаления и отмены удаления сообщений. Если вы хотите удалить сообщение, то вызываете deleteMessage(), передавая номер почтового сообщения, которое подлежит удалению. Учтите, что нумерация начинается с 1, как это принято у почтового сервера. Само сообщение при этом лишь помечается на удаление и в дальнейших транзакциях не участвует. Реально оно будет удалено в момент отключения клиента от сервера. Если же вы поняли, что совершили ошибку, то можете просто вызвать undoDeletes(), после чего пометка на удаление будет снята, и вы сможете читать это сообщение. Правда, придется заново загрузить все почтовые сообщения на локальный компьютер. Класс POPException Следуя концепции объектно-ориентированного программирования, просто необходимо создать свой собственный класс обработки исключительной ситуации - POPException. Он не только расширяет стандартный класс исключения Exception, но и добавляет специальное расширение - поле why, хранящее в виде числа причину возникновения исключения. Для удобства в классе определяются несколько констант, дающих этому числу осмысленное название. Если вы, создавая объект класса POPException, зададите в его конструкторе причину сбоя, то внутри класса вспомогательный метод assignMessage() подберет соответствующее текстовое сообщение. Перехватив исключительную ситуацию класса POPException, можно получить или разумное текстовое описание методом getMessage(), или же код причины методом Завершая описание, советуем в дополнение к протоколу POP3 ознакомиться со следующими рабочими документами: RFC821 - Simple Mail Transfer Protocol; Команды протокола РОРЗ Успех и неудача выполнения команды отмечаются признаками статуса +ОК или
Листинг 1 // Базовый класс для приема сообщений от // Формируем пакет // Импортируем нужные классы // Главный класс реализации протокола POP3 // Номер порта POP3 // Константы класса // Поля класса // Конструктор по умолчанию // Этот конструктор создает файл протокола // Финализатор // Установить соединение с почтовым сервером logText("Creating an input stream..."); logText("Creating an output stream..."); // Слушаем ответ сервера // Отключаемся от сервера // Записать строку в файл протокола // Входим в почтовый сервер // Загрузить всю почту на компьютер пользователя // Перебираем сообщения на сервере // Возвращает пользователю текст сообщения. // Удаляет сообщение. Нумерация начинается с 1 // Отменить удаление сообщений, которые были // Этот внутренний класс предварительно сохраняет // Возвращает true, если последняя команда if(!buff.startsWith(S_OK)) // Записать данные во временный буфер // Считать данные из временного буфера // Возвратить данные без статусного признака // Получить комментарий сервера к последней tmpStr = cutOffStatus(); // Внутренний класс для представления команды, // Получить ответ на служебную команду try { tmpBuff.append(ir.readLine()); } // Считать почтовое сообщение try // Метод-оболочка для выполнения типичной команды // Команды передачи имени пользователя // Команды передачи пароля // Команда завершения сеанса работы с почтой // Команда удаления сообщения // Команда отмены удаления // Получить информацию о сообщении // Команда чтения сообщения с сервера Листинг 2 // Вспомогательный класс представляет исключения, // Формируем пакет public class POPException extends Exception // Причина возникновения исключения // Конструктор по умолчанию // Конструктор со строкой // Конструктор, в котором задается причина // Задать строку, соответствующую причине // Возвращает причину исключительной ситуации 16.02.2006 |
VSESMI.ru — новости в СМИ.
Tur-Hotel.ru — отзывы об отелях
|
|
Copyright © 2002—2012 ООО "Хостмэйк" Телефон в Москве: +7 (495) 223-46-50 Телефон в Санкт-Петербурге: +7 (812) 448-38-90 Тел./Факс: +7 (8636) 237-836 E-mail: 2006 |