Архиватор jar
Архиватор jar
Для упаковки нескольких файлов в один архивный файл, со сжатием или без сжатия., в технологии Java разработан формат JAR. Имя архивного jar-файла может быть любым, но обычно оно получает расширение jar. Способ упаковки и сжатия основан на методе ZIP. Название JAR (Java ARchive) перекликается с названием известной утилиты TAR (Tape ARchive), разработанной в UNIX.
Отличие jar-файлов от zip-файлов только в том, что в первые автоматически включается каталог META-INF, содержащий несколько файлов с информацией об упакованных в архив файлах.
Архивные файлы очень удобно использовать в апплетах, поскольку весь архив загружается по сети сразу же, одним запросом. Все файлы апплета с байт-кодами, изображениями, звуковые файлы упаковываются в один или несколько архивов. Для их загрузки достаточно в теге <appiet> указать имена архивов в параметре archive, например:
<applet code = "MillAnim.class" archive = "first.jar, second.jar"
width = "100%" height = "100%"></applet>
Основной файл MillAnim.class должен находиться в каком-либо из архивных файлов first.jar или second.jar. Остальные файлы отыскиваются в архивных файлах, а если не найдены там, то на сервере, в том же каталоге, что и HTML-файл. Впрочем, файлы апплета можно упаковать и в zip-архив, со сжатием или без сжатия.
Архивные файлы удобно использовать и в приложениях (applications). Все файлы приложения упаковываются в архив, например, appl.jar. Приложение выполняется прямо из архива, интерпретатор запускается с параметром -jar, например:
Java -jar appl.jar
Имя основного класса приложения, содержащего метод main (), указывается в файле MANIFEST.MF, речь о котором пойдет чуть ниже.
Архивные файлы удобны и просты для компактного хранения всей необходимой для работы программы информации. С файлами архива можно работать прямо из архива, не распаковывая их, с помощью классов пакета
java.util.jar.
Файл INDEX.LIST
Файл INDEX.LIST
Для ускорения поиска файлов и более быстрой их загрузки можно создать файл поиска INDEX.LIST. Это делается после создания архива. Утилита jar запускается еще раз с параметром
-i,
например:
jar -i Base.jar
После этого в каталоге META-INF архива появляется файл INDEX.LIST. На Рисунок П.З представлено, как создается файл поиска и как выглядит содержимое архива после его создания.
Файл описания MANIFEST.MF
Файл описания MANIFEST.MF
Файл MANIFEST.MF, расположенный в каталоге META-INF архивного файла, предназначен для нескольких целей:
перечисления файлов из архива, снабженных цифровой подписью;
перечисления компонентов JavaBeans, расположенных в архиве;
указания имени основного класса для выполнения-приложения из архива;
записи сведений о версии пакета.
Вся информация сначала записывается в обычном текстовом файле с любым именем, например, manif. Потом запускается утилита jar, в которой этот файл указывается как значение параметра т, например:
jar cmf manif Base.jar classes Base.class
Утилита проверяет правильность записей в файле manif и переносит их в файл MANIFEST.MF, добавляя свои записи.
Файл описания manif должен быть написан по строгим правилам, изложенным в спецификации JAR File Specification. Ее можно найти в документации Java 2 SDK, в файле docs\guide\jar\jar.html.
Например, если мы хотим выполнять приложение с главным файлом Base.class из архива Base.jar, то файл manif должен содержать как минимум две строки:
Main-Class: Base
Первая строка содержит относительный путь к главному классу, но не к файлу, т. е. без расширения class. В этой строке каждый символ имеет значение, даже пробел. Вторая строка пустая — файл обязательно должен заканчиваться пустой строкой, точнее говоря, символом перевода строки '\n'.
После того как создан архив Base.jar, можно выполнять приложение прямо из него:
Java -jar Base.jar
Java на сервере
Java на сервере
Тенденция написания сетевых программ — побольше функций возложить на серверную часть программы и поменьше оставить клиентской части, сделав клиент "тонким", а сервер "толстым". Это позволяет, с одной стороны, использовать клиентскую часть программы на самых старых и маломощных компьютерах, а с другой стороны, облегчает модификацию программы — все изменения достаточно сделать только в одном месте, на сервере.
Сервер выполняет все больше функций, как говорят,
служб
или
сервисов
(services). Он и отправляет клиенту Web-страницы, и выполняет сервлеты, и связывается с базой данных, и обеспечивает транзакции. Такой многофункциональный сервер называется
сервером приложений
(application server). Большой популярностью сейчас пользуются серверы приложений WebLogic фирмы ВЕА Systems, IAS (Inprise Application Server) фирмы Borland, WebSphere фирмы IBM, OAS (Oracle Application Server). Важной характеристикой сервера приложений является способность расширять свои возможности путем включения новых модулей. Это удобно делать с помощью компонентов.
Фирма SUN Microsystems предложила свою систему компонентов EJB (Enterprise JavaBeans), включенную в Java 2 SDK Enterprise Edition. Подобно тому, как графические компоненты JavaBeans реализуют графический интерфейс пользователя, размещаясь в графических контейнерах, компоненты EJB реализуют различные службы на сервере, располагаясь в EJB-контейнерах. Этими контейнерами управляет EJB-сервер, включаемый в состав сервера приложений. В составе J2SDKEE EJB-сервер — это программа j2ee. Серверу приложений достаточно запустить эту программу, чтобы использовать компоненты EJB.
В отличие от JavaBeans у компонентов EJB не может быть графического интерфейса и ввода с клавиатуры. У них может отсутствовать даже консольный вывод. Контейнер EJB занимается не размещением компонентов, а созданием и удалением их объектов, связью с клиентами и другими компонентами, проверкой прав доступа и обеспечением транзакций.
Программы, оформляемые как EJB, могут быть двух типов: EntityBean и sessionBean. Они реализуют соответствующие интерфейсы из пакета javax.ejb. Первый тип EJB-компонентов удобен для создания программ, обращающихся к базам данных и выполняющих сложную обработку полученной информации. Компоненты этого типа могут работать сразу с несколькими клиентами. Второй тип EJB-компонентов более удобен для организации взаимодействия с клиентом. Компоненты этого типа бывают двух видов: сохраняющие свое состояние от запроса к запросу (stateful) и теряющие это состояние (stateless). Методами интерфейсов EntityBean и SessionBean контейнер EJB управляет поведением экземпляров класса. Если достаточно стандартного управления, то можно сделать пустую реализацию этих методов.
Кроме класса, реализующего интерфейс EntityBean или SessionBean, для создания компонента EJB необходимо создать еще два интерфейса, расширяющие интерфейсы вовноте и EjBObject. Первый интерфейс (home interface) служит для создания объекта EJB своими методами create (), для поиска и связи с этим объектом в процессе работы, и удаления его методом remove о. Второй интерфейс (remote interface) описывает методы компонента EJB. Интересная особенность технологии EJB — клиентская программа не образует объекты компонента EJB. Вместо этого она создает объекты home-и remote-интерфейсов и работает с этими объектами. Реализация home- и remote-интерфейсов, создание объектов компонента EJB и взаимодействие с ними остается на долю контейнера EJB.
Приведем простейший пример. Пусть мы решили обработать выборку из базы данных, занесенную в объект rs в сервлете листинга П.З, с помощью компонента EJB. Для простоты пусть обработка заключается в слиянии двух столбцов методом merge (). Напишем программу:
import java.rmi.RemoteException;
import javax.ejb.*;
public class MergeBean implements SessionBean{
public String merge(String si, String s2){
String s = si + " " + s2;
return s;
}
// Выполняется при обращении к методу create()
// интерфейса MergeHome. Играет роль конструктора класса
public void ejbCreate() {}
// Пустая реализация методов интерфейса
public void setSessionContext(SessionContext ctx){}
public void ejbRemoveO {}
public void ejbActivate()(}
public void ejbPassivate(){} }
public interface MergeHome extends EJBHome{
// Реализуется методом ejbCreate() класса MergeBean
Merge create)} throws CreateException, RemoteException;
}
public interface Merge extends EJBObject{
public double merge(String si, String s2)
throws RemoteException;
}
В сервлете листинга П.3 создаем объекты типа MergeHome и Merge и обращаемся к их методам:
import j avax.servlet.*;
import j avax.servlet.http.*;
import java.io.*;
import j avax.naming.*;
import j avax.rmi.PortableRemoteObj ect;
public class JDBCServlet extends HttpServlet {
MergeHome mh;
Merge m;
// Следующие определения
//.......
public void init(ServletConfig conf) throws ServletExceptionf
try( // Поиск объекта merge, реализующего MergeHome
InitialContext ic = new InitialContext(};
Object ref = ic.lookup("merge");
mh = (MergeHome)PortableRemoteObject.narrow(
ref, MergeHome.class); }catch(Exception e){
e.printStackTrace(); }
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletExceptionf
// Начало метода
//........
m = mh.create();
String s = m.merge(si, s2);
// и т. д.
}
}
После компиляции получаем EJB-приложение, состоящее из пяти файлов: JdbcServlet.html, JdbcServlet.class, MergeBean.class, MergeHome.class и Merge.class. Осталось правильно установить (deploy) его в контейнер EJB. Файлы jdbcserviet.html и JdbcServlet.class надо упаковать в один war-файл, остальные файлы — в один jar-файл, потом оба получившихся файла упаковать в один ear-файл (Enterprise ARchive). Кроме того, надо создать еще файл описания установки (deployment descriptor) в формате XML и занести его в архив. В этот файл, в частности, записывается имя "merge", по которому компонент отыскивается методом lookup ().
Все это можно сделать утилитой depioytool, входящей в состав Java 2 SDK Enterprise Edition. Эта же утилита позволяет проверить работу приложения и установить его в контейнер EJB. Надо только предварительно запустить EJB-сервер командой j2ee.
Впрочем, все файлы EJB-приложения можно упаковать в один jar-файл.
Многие серверы приложений и средства разработки, такие как Borland JBuilder и IBM Visual Age for Java, имеют в своем составе утилиты для установки EJB-приложений.
EJB-приложение готово. Теперь достаточно вызвать в браузере HTML-файл и заполнить появившуюся в окне форму.
Компоненты JavaBeans
Компоненты JavaBeans
Многие программисты предпочитают разрабатывать приложения с графическим интерфейсом пользователя с помощью визуальных средств разработки: JBuilder, Visual Age for Java, Visual Cafe и др. Эти средства позволяют помещать компоненты в контейнер графически, с помощью мыши. На Рисунок П.4 показано окно JBuilder 4.
Левый нижний угол окна занимает форма, на которой размещаются компоненты. Сами компоненты показаны ярлыками на панели компонентов, расположенной выше формы. На Рисунок П.4 на панели компонентов виден ярлык компонента Button, показанный прямоугольником с надписью ОК, ярлык компонента checkbox, показанный квадратиком с крестиком, ярлык компонента checkboxGroup, обозначенный группой радиокнопок. Далее видны ярлыки компонентов choice, Label, List и другие компоненты AWT.
Чтобы поместить компонент в форму, надо щелкнуть кнопкой мыши на ярлыке компонента, перенести курсор мыши в нужное место формы и щелкнуть кнопкой мыши еще раз.
Затем с помощью мыши необходимо установить нужные размеры компонента. При этом можно передвинуть компонент на другое место. На Рисунок П.4 в форму помещена кнопка типа Button.
П.1. Апплет, обращающийся к базе Oracle
Листинг П.1.
Апплет, обращающийся к базе Oracle
import j ava.awt.*;
import java.awt.event.*;
import j ava.applet.*;
import java.util.*;
import j ava.sql.*;
public class JdbcApplet extends Applet
implements ActionListener, Runnable{
private TextField tfl, tf2, tf3;
private TextArea ta;
private Button bl, b2;
private String url = "jdbc:oracle:thin:Slocalhost:1521:ORCL",
login = "scott",
password = "tiger",
query = "SELECT * FROM dept";
private Thread th;
private Vector results;
public void init(){
setBackground(Color.white) ;
try{
DriverManager.registerDriver(
new oracle.j dbc.driver.OracleDriver() ) ;
}catch(SQLException e){
System.err.println(e);
}
setLayout(null);
setFont(new Font("Serif", Font.PLAIN, 14));
Label l1 = new Label("URL базы:", Label.RIGHT);
11.setBounds(20, 30, 70, 25);
add(ll);
Label 12 = new Label("Имя:", Label.RIGHT);
12.setBounds(20, 60, 70, 25);
add(12);
Label 13 = new Label("Пароль:", Label.RIGHT);
13.setBounds(20, 90, 70, 25);
add(13);
tfl = new TextField(url, 30);
tfl.setBounds(100, 30, 280, 25);
add(tfl);
tf2 = new TextField(login, 30);
tf2.setBounds(100, 60, 280, 25);
add(tf2);
tf3 = new TextField(password, 30);
tf3.setBounds(100, 90, 280, 25);
add(tf3);
tf3.setEchoChar('*');
Label 14 = new Label("Запрос:", Label.LEFT);
14.setBounds(10, 120, 70, 25);
add(14);
ta = new TextArea(query, 5, 50, TextArea.SCROLLBARS_NONE);
ta.setBounds(10, 150, 370, 100);
add(ta);
Button bl = new Button("Отправить");
bl.setBounds(280, 260, 100, 30);
add(bl);
b1.addActionListener(this);
}
public void actionPerformed(ActionEvent ae){
url = tfl.getText() ;
login = tf2.getText();
password = tf3.getText();
query = ta.getText();
if (th == null){
th = new Thread(this);
th. start () ;
}
}
public void run(){
try{
Connection con =
DriverManager.getConnection(url, login, password);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
// Узнаем число столбцов
int n = rsmd.getColumnCount();
results = new Vector();
while (rs.nextOH String s = " ";
// Номера столбцов начинаются с 1!
for (int i = 1; i <= n; i++)
s += " " + rs.getObject(i);
results.addElement(s);
}
rs.close();
st.close () ;
con.closet);
repaint();
}catch(Exception e){
System, err.println(e);
}
repaint();
}
public void paint(Graphics g)(
if (results == null){
g.drawstring("Can't execute the query", 5, 30);
return;
}
int у = 30, n = results.size();
for (int i = 0; i < n; i++)
g.drawString((String)results.elementAt(i), 5, у += 20);
} }
Замечание
Замечание
В
главе 19
упоминалось, что для отладки сетевой программы удобно запустить и клиентскую, и серверную часть на одном компьютере, обращаясь к серверной части по адресу 127.0.0.1 или доменному имени localhost. He забывайте, что апплет может связаться по сети только с тем хостом, откуда он загружен. Следовательно, на компьютере должен работать Web-сервер. Если Web-сервер прослушивает порт 8080, то, чтобы загрузить HTML-страницу с апплетом, надо в браузере указывать адрес URL вида
. При этом учтите, что Web-сервер устанавливает свою иерархию каталогов, и каталог public на самом деле может быть каталогом usr/local/http/public или каким-нибудь другим.
Таким образом, JDBC позволяет проделать весь цикл работы с базой данных. Подробно со всеми возможностями JDBC можно познакомиться, прочитав спецификацию JDBC, имеющуюся в документации Java 2 SDK, в каталоге docs\guide\jdbc\spec\. Дополнения спецификации версии JDBC 2.0 изложены в каталоге docs\guide\jdbc\spec2\. В каталоге docs\guide\jdbc\getstart\ есть пособие по использованию JDBC.
Листинг П.2.
HTML-форма запроса к базе данных
<html>
<head>
<title>
JDBC Servlet</title>
</head>
<body>
<form method = "POST" action = "/servlet/JdbcServlet">
<pre>
URL базы: <input type = "text" size = "40" name = "url"
value = "jdbc:oracle:thin:@localhost:1521:ORCL">
Имя: <input type = "text" size = "40" name = "login"
value = "scott">
Пароль: <input type = "password" size = "40" name = "password"
value = "tiger">
Запрос:
<textarea rows = "5" cols "70" name = "query">
SELECT * FROM dept
</textarea>
<input type = "submit" value = "Послать">
</pre>
</form>
</body>
</html>
Сервлет получает из этой формы адрес базы url, имя login и пароль password пользователя, а также запрос query. Он обращается к базе данных Oracle через драйвер JDBC Oracle Thin, формирует полученный ответ в виде HTML-страницы и отправляет браузеру.
П.3 . Сервлет, выполняющий запрос к базе Oracle i
Листинг П.3
. Сервлет, выполняющий запрос к базе Oracle i
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import j ava.sql.*;
public class JdbcServlet extends HttpServlet{ static)
try{
DriverManager.registerDriver(
new oracle.j dbc.driver.OracleDriver());
)catch(SQLException e){
System.err.println(e) ;
}
)
private Vector results = new Vector();
private int n;
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException{
ServletExceptionf String url = req.getParameter("url") ,
login = req.getParameter("login") ,
password = req.getParameter("password") ,
query = req.getParameter("query");
// Задаем MIME-тип и кодировку для выходного потока pw
resp.setContentType("text/html;charset=windows-1251");
PrintWriter pw = resp.getWriter();
try{
Connection con =
DriverManager.getConnection(url, login, password);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
n = rsmd.getColumnCount();
while (rs.next()){
String s = " ";
for (int i = 1; i <= n; i++)
s += " " + rs.getObject(i);
results.addElement(s);
}
rs.close();
st.close();
con.close();
}catch(SQLException e){
pw.println("From doPostf): " + e) ;
}
pw.println("<html>
<head>
<title>
Answers</titlex/head>
");
рw.рrintln("<body>
<h2>
Результаты 3anpoca</h2>
");
n = results.size();
for (int i = 0; i < n; i++)
pw.println((String)results.elementAt(i) + "<br>
");
pw.println("</bodyx/html>
") ;
pw.flush() ;
pw.close () ;
}
}
Применение сервлета позволило "облегчить" клиент — браузер не загружает апплет, а только отправляет запрос и получает ответ. Вся обработка запроса ведется в сервлете на сервере.
В системе J2SDKEE (Java 2 SDK Enterprise Edition) HTML-файл и сервлет образуют один Web-компонент. Они упаковываются в один файл с расширением war (web archive) и помещаются в так называемый Web-контейнер, управляемый Web-сервером, расширенным средствами J2SDKEE.
Переход к Swing
Переход к Swing
В
части 3
мы подробно рассмотрели возможности графической библиотеки AWT. Там же мы заметили, что в состав Java 2 SDK входит еще одна графическая библиотека, Swing, с более широкими возможностями, чем AWT. Фирма SUN настоятельно рекомендует использовать Swing, а не AWT, но, во-первых, Swing требует больше ресурсов, что существенно для российского разработчика, во-вторых, большинство браузеров не имеет в своем составе Swing. В-третьих, удобнее сначала познакомиться с библиотекой AWT, а уже потом изучать Swing.
Все примеры графических программ, приведенные в книге, будут выполняться методами библиотеки Swing после небольшой переделки:
1. Добавьте в заголовок строку import javax.swing.*;.
2. Поменяйте Frame на JFrame, Applet на JApplet, Component нa JComponent, Panel на JPanei. He расширяйте свои классы от класса canvas, используйте jpanei или другие контейнеры Swing.
3. Замените компоненты AWT на близкие к ним компоненты Swing. Чаще всего надо просто приписать букву j: JButton, JcheckBox, JDialog, jList, JMenu и т. д. Закомментируйте временно строку import java.awt.*; и попробуйте откомпилировать программу. Компилятор покажет, какие компоненты требуют замены.
4. Включите в конструктор класса, расширяющего JFrame, строку Container с = getContentPane (); и располагайте все компоненты в контейнере с, Т. е. пишите c.add(), с.setLayout ().
5. Класс jFrame содержит средства закрытия своего окна, надо только настроить их. Вы можете убрать addwindowListener(...) и включить в конструктор обращение К методу setDefaultCloseQperation(JFrame.EXITJB_CLOSE).
6. В прямых подклассах класса jpanei замените метод paint о на paintcomponent () и удалите метод update о. Класс jpanei автоматически производит двойную буферизацию и надобности в методе update о больше нет. Уберите весь код двойной буферизации. В начало метода paintcomponent () включите обращение super.paintcomponent (g). Из подклассов классов JFrame, joialog, JAppiet метод paintcomponent () надо переместить в другие компоненты, например, JButton, JLabel, jpanei.
7. Используйте вместо класса image класс imageicon. Конструкторы этого класса выполнят необходимое преобразование. Класс imageicon автоматически применяет методы класса MediaTracker для ожидания окончания загрузки.
8. При создании апплетов расширением класса JAppiet не забывайте, что в классе Applet менеджером размещения по умолчанию служит класс FiowLayout, а в классе JAppiet менеджер размещения по умолчанию
BorderLayout.
Пункты 4 и 6 требуют пояснения. Окно верхнего уровня в Swing, такое как JFrame, содержит
корневую панель
(root pane), на которой размещена
слоеная панель
(layered pane). Компоненты на слоеной панели можно размещать несколькими слоями, перекрывая друг друга. В одном из слоев находится
панель содержимого
(content pane) и
строка меню
(menu bar). Поверх самого верхнего слоя расположена
прозрачная панель
(glass pane). Поэтому нельзя просто поместить компонент в окно верхнего уровня. Его надо "положить" на какую-нибудь панель. Пункт 4 рекомендует размещать компоненты на панели содержимого.
Откомпилировав и запустив измененную программу, вы увидите, что ее внешний вид изменился, чаще всего не в лучшую сторону. Теперь надо настроить компоненты Swing. Библиотека Swing предоставляет для этого широчайшие возможности.
П.1. Правила употребления утилиты jar
Рисунок П.1.
Правила употребления утилиты jar
После буквы, без пробела, можно написать одну или несколько букв, перечисленных в квадратных скобках. Они означают следующее:
v (verbose) — выводить сообщения о процессе работы с архивом в стандартный вывод;
f (file) — записанный далее параметр jar-file показывает имя архивного файла;
m (manifest) — записанный далее параметр manifest-file показывает имя файла описания;
о (нуль) — не сжимать файлы, записывая их в архив;
м (manifest) — не создавать файл описания;
Параметр -i (index) предписывает создать
в
архиве файл INDEX.LIST. Он используется уже после формирования архивного файла.
После буквенных параметров-файлов через пробел записывается имя архивного файла jar-file, потом, через пробел, имя файла описания manifest-file, затем перечисляются имена файлов, которые надо занести в архив или извлечь из архива. Если это имена каталогов, то операция выполняется рекурсивно со всеми файлами каталога.
Перед первым именем каталога может стоять параметр -с. Конструкция -с dir означает, что на время выполнения утилиты jar текущим каталогом станет каталог dir. ,
Необязательные параметры занесены в квадратные скобки.
Итак, в конце командной строки должно быть записано хотя бы одно имя файла или каталога. Если среди параметров есть буква f, то первый из этих файлов понимается как архивный jar-файл. Если среди параметров находится буква т, то первый файл понимается как файл описания (manifest-file). Если среди параметров присутствуют обе буквы, то имя архивного файла и имя файла описания должны идти в том же порядке, что и буквы f и т.
Если параметр f и имя архивного файла отсутствуют, то архивным файлом будет служить стандартный вывод.
П.2. Работа с утилитой jar
Рисунок П.2.
Работа с утилитой jar
Если параметр m и имя файла описания отсутствуют, то по умолчанию файл MANIFEST.MF, лежащий в каталоге META-INF архивного файла, будет содержать только номер версии.
На Рисунок П.2 показан процесс создания архива Base.jar в каталоге ch3. Сначала показано содержимое каталога ch3. Затем создается архив, в который включается файл Base.class и все содержимое подкаталога classes. Снова выводится содержимое каталога ch3. В нем появляется файл Base.jar. Потом выводится содержимое архива.
Как видите, в архиве создан каталог META-INF, а в нем файл MANIFEST.MF.
П.3. Создание файла поиска
Рисунок П.3.
Создание файла поиска
и фона, вид курсора мыши,
Рисунок П.4.
Окно JBuilder 4
Далее следует определить свойства (properties) компонента: текст, цвет текста и фона, вид курсора мыши, когда он появляется над компонентом Свойства определяются в окне свойств, расположенном справа от формы В левой колонке окна перечислены имена свойств, в правую колонку надо записать их значения. На Рисунок П.4 свойству label — надписи на кнопке — дано значение Выполнить. Это значение тут же появляется на кнопке
Потом можно задать обработку событий, открыв вторую страницу окна свойств.
Для того чтобы компонент можно было применять в таком визуальном средстве разработки как JBuilder, он должен обладать дополнительными качествами. У него должен быть ярлык, помещаемый на панель компонентов. Среди полей компонента должны быть выделены свойства (properties), которые будут показаны в окне свойств Следует определить методы доступа
getXxx () /setXxx () /isXxx ()
к каждому свойству
Компонент, снабженный этими и другими необходимыми качествами, в технологии Java называется компонентом JavaBean. В него может входить один или несколько классов. Как правило, файлы этих классов упаковываются в jar-архив и отмечаются в файле MANIFEST.MF как Java-Bean: True.
Все компоненты AWT и Swing являются компонентами JavaBeans. Если вы создаете свой графический компонент по правилам, изложенным в
части 3,
то вы тоже получаете свой JavaBean. Но для того чтобы не упустить каких-либо важных качеств JavaBean, лучше использовать для их разработки специальные средства.
Фирма SUN поставляет набор необходимых утилит и классов BDK (Beans Development Kit) для разработки JavaBeans. Так же, как и SDK, этот набор хранится на сайте фирмы в виде самораспаковывающегося архива, например, bdkl_l-win.exe. Его содержимое распаковывается в один каталог, например, D:\bdkl.l. После перехода в каталог bdkl.l\beanbox\ и запуска файла run.bat (или run.sh в UNIX) открываются несколько окон утилиты Bean-Box, работа с которой ведется по тому же принципу, что и в визуальных средствах разработки.
Правила оформления компонентов JavaBeans изложены в спецификации JavaBeans API Specification, которую можно найти по адресу http://
java.sun.com/products/javabeans/docs/spec.html.
Визуальные средства разработки — это не основное применение JavaBeans. Главное достоинство компонентов, оформленных как JavaBeans, в том, что они без труда встраиваются в любое приложение. Более того, приложение можно собрать из готовых JavaBeans как из строительных блоков, остается только настроить их свойства.
Специалисты пророчат большое будущее компонентному программированию. Они считают, что скоро будут созданы тысячи компонентов JavaBeans на все случаи жизни и программирование сведется к поиску в Internet нужных компонентов и сборке из них приложения.
Сервлеты
Сервлеты
В
главе 19
была упомянута технология CGI. Ее суть в том, что сетевой клиент, обычно браузер, посылает Web-серверу информацию вместе с указанием программы, которая будет обрабатывать эту информацию. Web-сервер, получив информацию, запускает программу, передает информацию на ее стандартный ввод и ждет окончания обработки. Результаты обработки программа отправляет на свой стандартный вывод, Web-сервер забирает их оттуда и отправляет клиенту. Написать программу можно на любом языке, лишь бы Web-сервер мог взаимодействовать с ней.
В технологии Java такие программы оформляются как
сервлеты
(servlets). Это название не случайно похоже на название "апплеты". Сервлет на Web-сервере играет такую же роль, что и апплет в браузере, расширяя его возможности.
Чтобы Web-сервер мог выполнять сервлеты, в его состав должна входить JVM и средства связи с сервлетами. Обычно все это поставляется в виде отдельного модуля, встраиваемого в Web-сервер. Существует много таких модулей: Resin, Tomcat, JRun, JServ. Они называются на жаргоне
сервлетными движками
(servlet engine).
Основные интерфейсы и классы, описывающие сервлеты, собраны в пакет javax.servlet. Расширения этих интерфейсов и классов, использующие конкретные особенности протокола HTTP, собраны в пакет javax.servlet.http. Еще два пакета— javax.servlet.jsp и javax.servlet.jsp.tagext — предназначены для связи сервлетов со скриптовым языком JSP (JavaServer Pages). Все эти пакеты входят в состав J2SDK Enterprise Edition. Они могут поставляться и отдельно как набор JSDK (Java Servlet Development Kit). Сервлет-ный движок должен реализовать эти интерфейсы.
Основу пакета javax.servlet составляет интерфейс servlet, частично реализованный в абстрактном классе GenericServiet и его абстрактном подклассе HttpServiet. Основу этого интерфейса составляют три метода:
init (Servietconfig config)
— задает начальные значения сервлету, играет ту же роль, что и метод init () в апплетах;
service(ServletRequest req, ServletResponse resp)
— выполняет обработку поступившей сервлету информации req и формирует ответ resp;
destroy ()
— завершает работу сервлета.
Опытный читатель уже понял, что вся работа сервлета сосредоточена в методе service о. Действительно, это единственный метод, не реализованный в классе GenericServiet. Достаточно расширить свой класс от класса . GenericServiet и реализовать в нем метод service (), чтобы получить собственный сервлет. Сервлетный движок, встроенный в Web-сервер, реализует интерфейсы ServletRequest и ServletResponse. Он Создает объекты req и resp, заносит всю поступившую информацию в объект req и передает этот объект сервлету вместе с пустым объектом resp. Сервлет принимает эти объекты как аргументы req и resp метода service о, обрабатывает информацию, заключенную в req, и оформляет ответ, заполняя объект resp. Движок забирает этот ответ и через Web-сервер отправляет его клиенту.
Основная информация, заключенная в объекте req, может быть получена методами read() и readLine() ИЗ байтового потока класса ServletlnputStream, непосредственно расширяющего класс inputstream, или из символьного потока класса BufferedReader. Эти потоки открываются, соответственно, методом req.getlnputStream() или методом req.getReader (). Дополнительные характеристики запроса можно получить многочисленными методами getxxxo объекта req. Кроме того, класс GenericServlet реализует массу методов getxxxo, позволяющих получить дополнительную информацию о конфигурации клиента.
Интерфейс servietResponse описывает симметричные методы для формирования ответа. Метод getoutputstreamo открывает байтовый поток класса ServletOutputStream, непосредственно расширяющего класс OutputStream. МеТОД getWriter () открывает символьный поток класса PrintWriter.
Итак, реализуя метод service!), надо получить информацию из входного потока объекта req, обработать ее и результат записать в выходной поток объекта resp.
Очень часто в объекте req содержится запрос к базе данных. В таком случае метод service о обращается через JDBC к базе данных и формирует ответ resp из полученного объекта ResultSet.
Протокол HTTP предлагает несколько методов передачи данных: GET, POST, PUT, DELETE. Для их использования класс GenericServlet расширен классом HttpServlet, находящимся В пакете javax.servlet.http. В этом классе есть методы для реализации каждого метода передачи данных:
doGet(HttpServletRequest req, HttpServletResponse resp)
doPost(HttpServletRequest req, HttpServletResponse resp)
doPut(HttpServletRequest req, HttpServletResponse resp)
doDelete(HttpServletRequest req, HttpServletResponse resp)
Для работы с конкретным HTTP-методом передачи данных достаточно расширить свой класс от класса HttpServlet и реализовать один из этих методов. Метод service () переопределять не надо, в классе HttpServlet он только определяет, каким HTTP-методом передан запрос клиента, и обращается к соответствующему методу doXxxo. Аргументы перечисленных методов req и resp — это объекты, реализующие Интерфейсы HttpServletRequest и HttpServletResponse, расширяющие интерфейсы ServletRequest и ServietResponse, соответственно.
Интерфейс HttpServletRequest к тому же описывает множество методов getxxx (), позволяющих получить дополнительные свойства запроса req.
Интерфейс HttpServletResponse описывает методы addxxxO и setxxxo, дополняющие ответ resp, и статические константы с кодами ответа Web-сервера.
В листингах П.2 и П.З те же действия, что выполняет программа листинга П. 1, реализованы с помощью сервлета. Апплет теперь не нужен, в окно браузера выводится HTML-форма, описанная в листинге П.2.
Создание архива
Создание архива
Jar-архивы создаются с помощью классов пакета java.util.jar или с помощью утилиты командной строки jar.
Правила применения утилиты jar очень похожи на правила применения утилиты tar. Набрав в командной строке слово jar и нажав клавишу <Enter>, вы получите краткое пояснение, показанное на Рисунок П.1.
В строке
jar {ctxu}[vfmOM] [jar-file] [manifest-file] [-C dir] files...
зашифрованы правила применения утилиты. Фигурные скобки показывают, что после слова jar и пробела надо написать одну из букв с, t, x или и. Эти буквы означают следующие операции:
с (create) — создать новый архив;
t (table of contents) — вывести в стандартный вывод список содержимого архива;
х (extract) — извлечь из архива один или несколько файлов;
u (update) — обновить архив, заменив или добавив один или несколько файлов.
Связь с базами данных через JDBC
Связь с базами данных через JDBC
Большинство информации хранится не в файлах, а в базах данных. Приложение должно уметь связываться с базой данных для получения из нее информации или для помещения информации в базу данных. Дело здесь осложняется тем, что СУБД (системы управления базами данных) сильно отличаются друг от друга и совершенно по-разному управляют базами данных. Каждая СУБД предоставляет свой набор функций для доступа к базам данных, и приходится для каждой СУБД писать свое приложение Но что делать при работе по сети, когда неизвестно, какая СУБД управляет базой на сервере?
Выход был найден корпорацией Microsoft, создавшей набор интерфейсов ODBC (Open Database Connectivity) для связи с базами данных, оформленных как прототипы функций языка С. Эти прототипы одинаковы для любой СУБД, они просто описывают набор действий с таблицами базы данных. В приложение, обращающееся к базе данных, записываются вызовы функций ODBC. Для каждой системы управления базами данных разрабатывается так называемый
драйвер ODBC,
реализующий эти функции для конкретной СУБД. Драйвер просматривает приложение, находит обращения к базе данных, передает их СУБД, получает от нее результаты и подставляет их в приложение. Идея оказалась очень удачной, и использование ODBC для работы с базами данных стало общепринятым.
Фирма SUN подхватила эту идею и разработала набор интерфейсов и классов, названный JDBC, предназначенный для работы с базами данных. Эти интерфейсы и классы составили пакет java.sqi, входящий в J2SDK Standard Edition, и его расширение javax.sql, входящее в J2SDK Enterprise Edition.
Кроме классов с методами доступа к базам данных для каждой СУБД необходим драйвер JDBC — промежуточная программа, реализующая методы JDBC. Существуют четыре типа драйверов JDBC.
1. Драйвер, реализующий методы JDBC вызовами функций ODBC. Это так называемый
мост
(bridge) JDBC-ODBC. Непосредственную связь с базой при этом осуществляет драйвер ODBC.
2. Драйвер, реализующий методы JDBC вызовами функций API самой СУБД.
3. Драйвер, реализующий методы JDBC вызовами функций сетевого протокола, независимого от СУБД. Этот протокол должен быть, затем, реализован средствами СУБД.
4. Драйвер, реализующий методы JDBC вызовами функций сетевого протокола СУБД.
Перед обращением к базе данных следует установить нужный драйвер, например, мост JDBC-ODBC:
try{
Class dr = sun.jdbc.odbc.JdbcOdbcDriver.class;
}catch(ClassNotFoundException e){
System.err.println("JDBC-ODBC bridge not found " + e);
}
Объект dr не понадобится в программе, но таков синтаксис. Другой способ установки драйвера показан в листинге П.1.
После того как драйвер установлен, надо связаться с базой данных. Методы связи описаны в интерфейсе connection. Экземпляр класса, реализующего этот интерфейс, можно получить одним из статических методов getConnection () класса DriverManager, например:
String url = "jdbc:odbc:mydb";
String login = "habib";
String password = "lnF4vb";
Connection qon = DriverManager.getConnection(url, login, password);
Обратите внимание на то, как формируется адрес базы данных url. Он начинается со строки "jdbc:", потом записывается
подпротокол
(subprotocol), в данном примере используется мост JDBC-ODBC, поэтому записывается "odbc:". Далее указывается адрес (subname) по правилам подпротокола, здесь просто имя локальной базы "mydb". Второй и третий аргументы — это имя и пароль для соединения с базой данных.
Если в вашей вычислительной системе установлен пакет javax.sql, то вместо класса DriverManager лучше использовать интерфейс DataSource.
Связавшись с базой данных, можно посылать запросы. Запрос хранится в объекте, реализующем интерфейс statement. Этот объект создается методом createstatement (), описанным в интерфейсе connection. Например:
Statement st = con.createStatement();
Затем запрос (query) заносится в этот объект методом execute () и потом выполняется методом getResultSet(). В простых случаях это можно сделать одним методом executeQuery (), например:
ResultSet rs = st.executeQuery("SELECT name, code FROM tbll");
Здесь из таблицы tbll извлекается содержимое двух столбцов name и code и заносится в объект rs класса, реализующего интерфейс ResultSet.
SQL-операторы INSERT, UPDATE, DELETE, CREATE TABLE и другие в простых случаях ВЫПОЛНЯЮТСЯ методом executeUpdate ().
Остается методом next () перебрать элементы объекта rs — строки полученных столбцов — и извлечь данные многочисленными методами getxxx () интерфейса ResultSet:
while (rs.next()){
emp[i] = rs.getString("name") ;
num[i] = rs.getlnt("code");
i++; }
Методы интерфейса ResuitsetMetaData позволяют узнать количество полученных столбцов, их имена и типы, название таблицы, имя ее владельца и прочие сведения о представленных в объекте rs сведениях.
Если объект st получен методом
Statement st = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_OPDATABLE);
то можно перейти к предыдущему элементу методом previous (), к первому элементу — методом first о, к последнему — методом last о. Можно также изменять объект rs методами updatexxx () и даже изменять, удалять и добавлять соответствующие строки базы данных. Не все драйверы обеспечивают эти возможности, поэтому, надо проверить реальный тип объекта rs методами rs.getType() И rs.getConcurrency().
Интерфейс Statement расширен интерфейсом PreparedStatement, тоже позволяющим изменять объект ResultSet методами setxxxo.
Интерфейс Preparedstatement, в свою очередь, расширен интерфейсом caiiablestatement, в котором описаны методы выполнения хранимых процедур.
В листинге П.1 приведен типичный пример запроса к базе Oracle через драйвер Oracle Thin. Апплет выводит в окно браузера четыре поля ввода для адреса базы, имени и пароля пользователя, и запроса. По умолчанию формируется запрос к стартовой базе Oracle, расположенной на локальном компьютере. Результат запроса выводится в окно браузера.
и все. Книга прочитана. Теперь
Заключение
Ну вот и все. Книга прочитана. Теперь вы можете уверенно чувствовать себя в мире Java, свободно разбираться в новых технологиях и создавать свои приложения на самом современном уровне. Конечно, в этой книге мы не смогли подробно разобрать все аспекты технологии Java, но, зная основные приемы, вы сможете легко освоить все ее новые методы. Успехов вам!
показывает, как легко можно получить файл из Internet, пользуясь методом openStream().
Листинг 19.1 показывает, как легко можно получить файл из Internet, пользуясь методом openStream().
Получение Web-страницы
Листинг 19.1.
Получение Web-страницы
import java.net.*;
import j ava.io.*;
class SimpleURL{
public static void main(String[] args){
try{
URL bhv = new URL("
");
BufferedReader br = new BufferedReader(
new InputStreamReader(bhv.openStream()));
String line;
while ((line = br.readLine()) != null)
System.out.println(line);
br.close();
}catch(MalformedURLException me){
System.err.println("Unknown host: " + me);
System.exit(0);
}catch(IOException ioe){
System.err.println("Input error: " + ioe);
}
}
}
Если вам надо не только получить информацию с хоста, но и узнать ее тип: текст, гипертекст, архивный файл, изображение, звук, или выяснить длину файла, или передать информацию на хост, то необходимо сначала методом openConnection () создать объект класса URLConnection или его подкласса
HttpURLConnection.
После создания объекта соединение еще не установлено, и можно задать параметры связи. Это делается следующими методами:
setDoOutput (boolean out)
— если аргумент out равен true, то передача пойдет от клиента на хост; значение по умолчанию false;
setDoinput (boolean in)
— если аргумент in равен true, то передача пойдет с хоста к клиенту; значение по умолчанию true, но если уже выполнено setDoOutput(true), то значение по умолчанию равно false;
setUseCaches (boolean cache)
— если аргумент cache равен false, то передача пойдет без кэширования, если true, то принимается режим по умолчанию;
setDefaultUseCaches(boolean default)
— если аргумент default равен true, то принимается режим кэширования, предусмотренный протоколом;
setRequestProperty(String name, String value) —
добавляет параметр name со значением value к заголовку посылаемого сообщения.
После задания параметров нужно установить соединение методом connect (). После соединения задание параметров уже невозможно. Следует учесть, что некоторые методы доступа getxxxo, которым надо получить свои значения с хоста, автоматически устанавливают соединение, и обращение к методу connect () становится излишним.
Web- сервер возвращает информацию, запрошенную клиентом, вместе с заголовком, сведения из которого можно получить методами getxxxo, например:
getcontentType ()
— возвращает строку типа string, показывающую тип пересланной информации, например, "text/html", или null, если сервер его не указал;
getcontentLength ()
— возвращает длину полученной информации в байтах или — 1, если сервер ее не указал;
getcontent ()
— возвращает полученную информацию в виде объекта типа Object;
getContentEncoding ()
— возвращает строку типа string с кодировкой полученной информации, или null, если сервер ее не указал.
Два метода возвращают потоки ввода/вывода, созданные для данного соединения:
getlnputStream()
— возвращает входной поток типа InputStream;
getOutputStream()
— возвращает выходной поток типа OutputStream.
Прочие методы, а их около двадцати, возвращают различные параметры соединения.
Обращение к методу bhv.openstreamo, записанное в листинге 19.1, — это, на самом деле, сокращение записи
bhv.openConnection().getlnputStream()
В листинге 19.2 показано, как переслать строку текста по адресу URL.
Web-сервер, который получает эту строку, не знает, что делать с полученной информацией. Занести ее в файл? Но с каким именем, и есть ли у него право создавать файлы? Переслать на другую машину? Но куда?
Выход был найден в системе CGI (Common Gateway Interface), которая вкратце действует следующим образом. При посылке сообщения мы указываем URL исполнимого файла некоторой программы, размещенной на машине-сервере. Получив сообщение, Web-сервер запускает эту программу и передает сообщение на ее стандартный ввод. Вот программа-то и знает, что делать с полученным сообщением. Она обрабатывает сообщение и выводит результат обработки на свой стандартный вывод. Web-сервер подключается к стандартному выводу, принимает результат и отправляет его обратно клиенту.
CGI-программу можно написать на любом языке: С, C++, Pascal, Perl, PHP, лишь бы у нее был стандартный ввод и стандартный вывод. Можно написать ее и на Java, но в технологии Java есть более изящное решение этой задачи с помощью сервлетов (servlets). CGI-программы обычно лежат на сервере в каталоге cgi-bin.
Посылка строки по адресу URL
Листинг 19.2.
Посылка строки по адресу URL
import java.net.*;
import java.io.*;
class PostURL{
public static void main(String[] args){
String req = "This text is posting to URL";
try{
// Указываем URL нужной CGI-программы
URL url = new URL("
");
// Создаем объект uc
URLConnection uc = url.openConnection();
// Собираемся отправлять
uc.setDoOutput(true);
// и получать сообщения
uc.setDoInput(true);
// без кэширования
uc.setUseCaches(false);
// Задаем тип
uc.setRequestProperty("content-type",
"application/octet-stream");
// и длину сообщения
uc.setRequestProperty("content-length", "" + req.length());
// Устанавливаем соединение
uc.connect();
// Открываем выходной поток
DataOutputStream dos = new DataOutputStream( uc.getOutputStreamO);
// и выводим в него сообщение, посылая его на адрес
URL dos.writeBytes(req);
// Закрываем выходной поток
dos.close();
// Открываем входной поток для ответа сервера
BufferedReader br = new BufferedReader(new InputStreamReader(
uc.getlnputStream() )) ;
String res = null;
// Читаем ответ сервера и выводим его на консоль
while ((res = br.readLine()) != null)
System.out.println(res);
br.close () ;
}catch(MalformedURLException me){
System.err.println(me);
}catch(UnknownHostException he){
System.err.println(he);
}catch(UnknownServiceException se){
System.err.println(se);
}catch(IOException ioe){
System.err.println(ioe);
}
}
}
Упрощенный HTTP-клиент
Листинг 19.3.
Упрощенный HTTP-клиент
import java.net.*;
import java.io.*;
import java.util.*;
class Client{
public static void main(String[] args){
if (args.length != 3){
System.err.println("Usage: Client host port file");
System.exit(0) ;
}
String host = args[0];
int port = Integer.parselnt(args[1]);
String file = args[2];
try{
Socket sock = new Socket(host, port);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(
sock.getOutputStreamf)), true);
pw.println("POST " + file + " HTTP/1.l\n");
BufferedReader br = new BufferedReader(new InputStreamReader(
sock.getlnputStream() ) ) ;
String line = null;
line = br.readLine();
StringTokenizer st = new StringTokenizer(line);
String code = null;
if ((st.countTokens() >
= 2) && st.nextToken().equals("POST")){
if ((code = st.nextToken()) != "200") {
System.err.println("File not found, code = " + code);
System.exit (0);
}
}
while ((line = br.readLine()) != null)
System.out.println{line);
sock.close();
}catch(Exception e){
System.err.println(e);
}
}
}
Закрытие потоков ввода/вывода вызывает закрытие сокета. Обратно, закрытие сокета закрывает и потоки.
Для создания сервера в пакете java.net есть класс serversocket. В конструкторе этого класса указывается номер порта
ServerSocket(int port)
Основной метод этого класса accept () ожидает поступления запроса. Когда запрос получен, метод устанавливает соединение с клиентом и возвращает объект класса socket, через который сервер будет обмениваться информацией с клиентом.
Упрощенный HTTP-сервер
Листинг 19.4.
Упрощенный HTTP-сервер
import j ava.net.*;
import java.io.*;
import j ava.uti1.*;
class Server!
public static void main(String[] args){
try{
ServerSocket ss = new ServerSocket(Integer.parselnt(args[0]));
while (true)
new HttpConnect(ss.accept());
}catch(ArraylndexOutOfBoundsException ae){
System.err.println("Usage: Server port");
System.exit(0);
}catch(IOException e){
System.out.println(e);
}
}
}
class HttpConnect extends Thread{
private Socket sock;
HttpConnect(Socket s) {
sock = s;
setPriority(NORM_PRIORITY - 1);
start {) ;
}
public void run(){
try{
PrintWriter pw = new PrintWriter(new OutputStreamWriter(
sock.getOutputStream()}, true);
BufferedReader br = new BufferedReader(new InputStreamReader(
sock.getlnputStream() ) ) ;
String req = br.readLine();
System.out.println("Request: " + req);
StringTokenizer st = new StringTokenizer(req);
if ((st.countTokens() >
= 2) && st.nextToken().equals("POST")){
if ((req = st.nextToken()).endsWith("/") II req.equals(""))
req += "index.html";
try{
File f = new File(req);
BufferedReader bfr =
new BufferedReader(new FileReader(f));
char[] data = new char[(int)f.length()];
bfr.read(data);
pw.println("HTTP/1.1 200 OK\n");
pw.write(data);
pw.flush();
}catch(FileNotFoundException fe){
pw.println("HTTP/1.1 404 Not FoundXn");
}catch(lOException ioe){
System.out.println(ioe);
}
}else pw.println("HTTP/l.l 400 Bad RequestW);
sock.close();
}catch(IOException e){
System.out.println(e);
}
}
}
Вначале следует запустить сервер, указав номер порта, например:
Java Server 8080
Затем надо запустить клиент, указав IP-адрес или доменное имя хоста, номер порта и имя файла:
Java Client localhost 8080 Server.Java
Сервер отыскивает файл Server.java в своем текущем каталоге и посылает его клиенту. Клиент выводит содержимое этого класса в стандартный вывод и завершает работу. Сервер продолжает работать, ожидая следующего запроса.
Замечание
Замечание
Программы, реализующие стек протоколов TCP/IP, всегда создают так называемую "петлю" с адресом 127.0.0.1 и доменным именем localhost. Это адрес самого компьютера. Он используется для отладки приложений клиент-сервер. Вы можете запускать клиент и сервер на одной машине, пользуясь этим адресом.
Посылка дейтаграмм по протоколу UDP
Листинг 19.5.
Посылка дейтаграмм по протоколу UDP
import java.net.*;
import java.io.*;
class Sender{
private String host;
private int port;
Sender(String host, int port){
this.host = host;
this.port = port;
}
private void sendMessage(String mes){
try{
byte[] data = mes.getBytes();
InetAddress addr = InetAddress.getByName(host);
DatagramPacket pack =
new DatagramPacket(data, data.length, addr, port);
DatagramSocket ds = new DatagramSocket();
ds.send(pack);
ds.close();
}catch(IOException e){
System.err.println(e);
}
}
public static void main(String[] args){
Sender sndr = new Sender("localhost", 1050);
for (int k = 0; k < args.length; k++)
sndr.sendMessage(args[k]);
}
}
Прием дейтаграмм по протоколу UDP
Листинг 19.6.
Прием дейтаграмм по протоколу UDP
import j ava.net.*;
import java.io.*;
class Recipient{
public static void main(String[] args)(
try{
DatagramSocket ds = new DatagramSocket(1050);
while (true){
DatagramPacket pack =
new DatagramPacket(new byte[1024], 1024);
ds.receive(pack);
System.out.println(new String(pack.getData()));
}
)catch(Exception e){
System.out.println(e);
}
}
}
Работа по протоколу TCP
Работа по протоколу TCP
Программы-серверы, прослушивающие свои порты, работают под управлением операционной системы. У машин-серверов могут быть самые разные операционные системы, особенности которых передаются программам-серверам.
Чтобы сгладить различия в реализациях разных серверов, между сервером и портом введен промежуточный программный слой, названный
сокетом
(socket). Английское слово socket переводится как электрический разъем, розетка. Так же как к розетке при помощи вилки можно подключить любой электрический прибор, лишь бы он был рассчитан на 220 В и 50 Гц, к соке-ту можно присоединить любой клиент, лишь бы он работал по тому же протоколу, что и сервер. Каждый сокет связан (bind) с одним портом, говорят, что сокет прослушивает (listen) порт. Соединение с помощью сокетов устанавливается так.
1. Сервер создает сокет, прослушивающий порт сервера.
2. Клиент тоже создает сокет, через который связывается с сервером, сервер начинает устанавливать (accept) связь с клиентом.
3. Устанавливая связь, сервер создает новый сокет, прослушивающий порт с другим, новым номером, и сообщает этот номер клиенту.
4. Клиент посылает запрос на сервер через порт с новым номером.
После этого соединение становится совершенно симметричным — два сокета обмениваются информацией, а сервер через старый сокет продолжает прослушивать прежний порт, ожидая следующего клиента.
В Java сокет — это объект класса socket из пакета java.io. В классе шесть конструкторов, в которые разными способами заносится адрес хоста и номер порта. Чаще всего применяется конструктор
Socket(String host, int port)
Многочисленные методы доступа устанавливают и получают параметры со-кета. Мы не будем углубляться в их изучение. Нам понадобятся только методы, создающие потоки ввода/вывода:
getlnputStream()
— возвращает входной поток типа InputStream;
getOutputStream()
— возвращает выходной поток типа OutputStream.
Приведем пример получения файла с сервера по максимально упрощенному протоколу HTTP.
1. Клиент посылает серверу запрос на получение файла строкой "POST filename HTTP/1.l\n\n", где filename — строка с путем к файлу на сервере.
2. Сервер анализирует строку, отыскивает файл с именем filename и возвращает его клиенту. Если имя файла filename заканчивается наклонной чертой /, то сервер понимает его как имя каталога и возвращает файл in-dex.html, находящийся в этом каталоге.
3. Перед содержимым файла сервер посылает строку вида "HTTP/1.1 code OK\n\n", где code — это код ответа, одно из чисел: 200 — запрос удовлетворен, файл посылается; 400 — запрос не понят; 404 — файл не найден.
4. Сервер закрывает сокет и продолжает слушать порт, ожидая следующего запроса.
5. Клиент выводит содержимое полученного файла в стандартный вывод System, out или выводит код сообщения сервера в стандартный вывод сообщений System, err.
6. Клиент закрывает сокет, завершая связь.
Этот протокол реализуется в клиентской программе листинга 19.3 и серверной программе листинга 19.4.
Работа по протоколу UDP
Работа по протоколу UDP
Для посылки дейтаграмм отправитель и получатель создают сокеты дейта-граммного типа. В Java их представляет класс DatagramSocket. В классе три конструктора:
DatagramSocket ()
— создаваемый сокет присоединяется к любому свободному порту на локальной машине;
DatagramSocket (int port)
— создаваемый сокет присоединяется к порту port на локальной машине;
DatagramSocket(int port, InetAddress addr) — создаваемый СОКСТ при
соединяется к порту port; аргумент addr — один из адресов локальной машины.
Класс содержит массу методов доступа к параметрам сокета и, кроме того, методы отправки и приема дейтаграмм:
send(DatagramPacket pack)
— отправляет дейтаграмму, упакованную в пакет pack;
receive (DatagramPacket pack)
— дожидается получения дейтаграммы и заносит ее в пакет pack.
При обмене дейтаграммами соединение обычно не устанавливается, дейтаграммы посылаются наудачу, в расчете на то, что получатель ожидает их. Но можно установить соединение методом
connect(InetAddress addr, int port)
При этом устанавливается только одностороннее соединение с хостом по адресу addr и номером порта port — или на отправку или на прием дейтаграмм. Потом соединение можно разорвать методом
disconnect()
При посылке дейтаграммы по протоколу JJDP сначала создается сообщение в виде массива байтов, например,
String mes = "This is the sending message.";
byte[] data = mes.getBytes();
Потом записывается адрес — объект класса inetAddress, например:
InetAddress addr = InetAddress.getByName (host);
Затем сообщение упаковывается в пакет — объект класса DatagramPacket. При этом указывается массив данных, его длина, адрес и номер порта:
DatagramPacket pack = new DatagramPacket(data, data.length, addr, port)
Далее создается дейтаграммный сокет
DatagramSocket ds = new DatagramSocket()
и дейтаграмма отправляется
ds.send(pack)
После посылки всех дейтаграмм сокет закрывается, не дожидаясь какой-либо реакции со стороны получателя:
ds.close ()
Прием и распаковка дейтаграмм производится в обратном порядке, вместо метода send () применяется метод receive (DatagramPacket pack).
В листинге 19.5 показан пример класса Sender, посылающего сообщения, набираемые в командной строке, на localhost, порт номер 1050. Класс Recipient, описанный в листинге 19.6, принимает эти сообщения и выводит их в свой стандартный вывод.
Работа в WWW
Работа в WWW
Среди программного обеспечения Internet большое распространение получила информационная система WWW (World Wide Web), основанная на прикладном протоколе HTTP (Hypertext Transfer Protocol). В ней используется расширенная адресация, называемая URL (Uniform Resource Locator). Эта адресация имеет такие схемы:
Здесь необязательная часть authority — это пара имя:пароль для доступа к хосту, host — это IP-адрес или доменное имя хоста. Например:
ffle:///C:/text/html/index.htm
Если какой-то элемент URL отсутствует, то берется стандартное значение. Например, в первом примере номер порта port равен 80, а имя файла path — какой-то головной файл, определяемый хостом, чаще всего это файл с именем index.html. В третьем примере номер порта равен 21. В последнем примере в форме URL просто записано имя файла index.htm, расположенного на разделе С: жесткого диска той же самой машины.
В Java для работы с URL есть класс URL пакета java.net. Объект этого класса создается одним из шести конструкторов. В основном конструкторе
URL(String url)
задается расширенный адрес url в виде строки. Кроме методов доступа getxxxo, позволяющих получить элементы URL, в этом классе есть два интересных метода:
openConnection ()
— определяет связь с URL и возвращает объект класса
URLConnection;
openStream()
— устанавливает связь с URL и открывает входной поток в виде возвращаемого объекта класса inputstream.