Средства Java для организации работы в сети Основные задачи, которые реализуются при организации приложений архитектуры клиент-сервер: 1) Получить информацию с одной машины и переместить её на другую машину. Выполняется с помощью простейшего сетевого программирования. 2) Подключиться к базе данных, находящейся в сети. Выполняется с помощью библиотеки Java DataBase Connectivity (JDBC). 3) Представление услуг через web-сервер. Достигается через какой-либо web-сервер, который поддерживает технологию Java-сервлетов и Java Server Pages (JSP). 4) Удалённый запуск методов объектов Java на других компьютерах. Выполняется с помощью Remote Method Invocation (RMI) – удалённый вызов методов. 5) Использовать код, написанный на других языках и работающий в других архитектурах. Позволяет технология CORBA (Common Object Request Broker Architecture) – общая архитектура брокеров объектных запросов. 6) Изолировать бизнес-логику от соединения, особенно соединения с БД, включающего обработку транзакций и безопасность в корпоративных клиент-серверных системах. Реализуется при помощи EJB (Enterprise JavaBeans). 7) Простое динамическое добавление, использование и удаление устройств бытового оборудования и программного обслуживания, обеспечивающих определенный сервис для клиента сети. Обеспечивается при помощи Jini. Сервера и клиенты Различие между сервером и клиентом существенно на только когда клиент пытается подключиться к серверу. Как только они соединятся, происходит процесс двухстороннего общения и не важно, что один является сервером, а другой - клиентом. Итак, работа сервера - слушать соединение, и это выполняется с помощью специального создаваемого серверного объекта (сокета), который равен: сокет=IP+номер_порта. Работа клиента - попытаться создать соединение с сервером, что выполняется с помощью специального клиентского объекта (сокета). Как только соединение установлено, соединение превращается в потоковый объект ввода/вывода, и с этого момента можно рассматривать соединение как файл, который Вы можете читать, и в который Вы можете записывать данные. Единственная особенность, файл может обладать определенным интеллектом и обрабатывать передаваемые Вами команды. Эти функции обеспечиваются расширением программы сетевой библиотеки Java java.net.*;. Сокеты Сокет(гнездо, разъем) (сокет=IP+ПОРТ) - это программная абстракция, используемая для представления “терминалов” соединений между двумя машинами. Для такого соединения, существует сокет на каждой машине, и можно представить себе виртуальный “кабель” соединяющий две машины, каждый конец которого вставлен в сокет. В Java сокет создается для установления соединения с другой машиной. Для этого в JAVA используется два класса сокетов, основанных на потоках: ServerSocket – класс используемый сервером, чтобы “слушать” входящие соединения и Socket - используемый клиентом для инициирования соединения. Как только клиент создает соединение по сокету, ServerSocket возвращает ему с помощью метода accept() соответствующий объект Socket на сервере, по которому будет происходить связь со стороны сервера. Начиная с этого момента, появляется соединение Socket к Socket, и можно считать эти соединения одинаковыми, т.к. они действительно одинаковые. В распоряжение получаем 2 класса InputStream и OutputStream (либо с помощью соответствующих преобразователей, Reader и Writer)из сокета, который соответствующим образом представляет соединение, как потоковый объект ввода вывода. Можно использовать методы getInputStream( ) и getOutputStream( ) для создания соответствующих объектов InputStream и OutputStream. Сокеты TCP/IP клиентов Для создания сокета клиента используется конструктор: Socket(String hostname, int port)// создает сокет, соединяющий локальную хост-машину с именованной хост-машиной и портом; может выбрасывать исключение UnknownHostException или IOException Socket(InetAddress ipAddress, int port)// создает сокет, аналогичный предыдущему, но используется уже существующий объект класса InetAddres и порт; может выбрасывать исключение IOException Сокет может в любое время просматривать связанную с ним адресную и портовую информацию при помощи методов, представленных в табл. 3. 1. Таблица 3.1 Методы просмотра адресной и портовой информации Метод | Описание | InetAddress getInetAddress() | Возвращает InetAddress-объект, связанный с Socket-объектом | int getPort() | Возвращает удаленный порт, с которым соединен данный Socket-объект | int getLocalPort() | Возвращает локальный порт, с котрым соединен данный Socket-объект | После создания Socket-объект можно применять для получения доступа к связанным с ним потокам ввода/вывода. Данные потоки используются точно также как потоки ввода/вывода, описанные в лабораторной 1. Пример кода клиента показан ниже. Сокеты TCP/IP серверов Как было указано выше для создания сокетов серверов используется класс ServerSocket. Указанный класс используется для создания серверов, которые прослушивают либо локальные, либо удаленные программы клиента, чтобы соединяться с ними на опубликованных портах. Конструкторы класса ServerSocket: ServerSocket(int port);// создает сокет сервера на указанном порте с длиной очереди по умолчанию 50 ServerSocket(int port, int maxQueue);// создает сокет сервера на указанном порте с максимальной длиной очереди maxQueue ServerSocket(int port, int maxQueue, InetAddress localAddress);// создает сокет сервера на указанном порте с максимальной длиной очереди maxQueue Класс ServerSocket имеет дополнительный метод accept(), который является блокирующим вызовом: он будет ждать клиента, чтобы инициализировать связь, и затем вернет нормальный Socket-объект, котрый будет использоваться для связи с клиентом. После создания объекта ServerSocket его можно также применять для получения доступа к связанным с ним потокам ввода/вывода. Данные потоки используются точно также как потоки ввода/вывода, описанные в лабораторной 1. Пример кода сервера показан ниже. Рассмотрим пример. Необходимо создать приложение клиент-сервер, в котором клиент считывает строку с клавиатуры, отображает ее на экране, передает ее серверу, сервер отображает ее на экране, переводит в верхний регистр и передает клиенту, который, в свою очередь, снова отображает ее на экране. Листинг кода Программа сервера: import java.io.*;//импорт каталога, содержащего классы для ввода/вывода import java.net.*;//импорт каталога, содержащего классы для работы в сети Интернет public class server {//описание класса server public static void main(String[] arg) {//создание метода main, без которого Java-//интерпретатор не запустит класс, с входным параметром с именем args, который //является массивом объектов - представителей класса String. ServerSocket serverSocket = null;//объявляется объект класса ServerSocket Socket clientAccepted = null;//объявляется объект класса Socket ObjectInputStream sois = null;//объявляется байтовый поток ввода ObjectOutputStream soos = null;//объявляетя байтовый поток вывода try {//ключевое слово механизма обработки исключений System.out.println("server starting....");//вывод строки на консоль serverSocket = new ServerSocket(2525);//создание сокета сервера для //заданного порта clientAccepted = serverSocket.accept();//выполнение метода, которое //обеспечивает реальное подключение сервера к клиенту System.out.println("connection established....");//вывод строки на //консоль sois = new ObjectInputStream(clientAccepted.getInputStream());//создание потока ввода soos = new ObjectOutputStream(clientAccepted.getOutputStream());//создание потока вывода String clientMessageRecieved = (String)sois.readObject();//объявляется //строка и ей присваиваются данные потока ввода, представленные ввиде строки //(передано клиентом) while(!clientMessageRecieved.equals("quite"))//выполнение цикла: пока //строка не будет равна "quite" { System.out.println("message recieved: '"+clientMessageRecieved+"'");//выведение на консоль строки и значения строковой //переменной clientMessageRecieved = clientMessageRecieved.toUpperCase();//приведение символов строки к верхнему реестру soos.writeObject(clientMessageRecieved);//потоку вывода //присваивается значение строковой переменной (передается клиенту) clientMessageRecieved = (String)sois.readObject();//строке //присваиваются данные потока ввода, представленные ввиде строки (передано клиентом) } }catch(Exception e) {//обработка исключения типа Exception } finally {//исключение передается умалчиваемому обработчику try {//ключевое слово механизма обработки исключений sois.close();//закрывается поток ввода soos.close();//закрывается поток вывода clientAccepted.close();//закрывается сокет serverSocket.close();//происходит отключение сервера от //клиента } catch(Exception e) {//обработка исключения типа Exception e.printStackTrace();//вызывается метод исключения е } } } } Программа клиента: import java.io.*;//импорт каталога, содержащего классы для ввода/вывода import java.net.*;//импорт каталога, содержащего классы для работы в сети Интернет public class client {//описание класса client public static void main(String[] arg) {//создание метода main, без которого Java-//интерпретатор не запустит класс, с входным параметром с именем args, который //является массивом объектов - представителей класса String. try {//ключевое слово механизма обработки исключений System.out.println("server connecting....");//вывод строки на консоль Socket clientSocket = new Socket("127.0.0.1",2525);//установление //соединения между локальной машиной и указанным портом узла Интернет System.out.println("connection established....");//вывод строки на //консоль BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));//создание буферизированного символьного потока ввода ObjectOutputStream coos = new ObjectOutputStream(clientSocket.getOutputStream());//создание потока вывода ObjectInputStream cois = new ObjectInputStream(clientSocket.getInputStream());//создание потока ввода System.out.println("Enter any string to send to server \n\t('quite' - programme terminate)");//выод строки на консоль String clientMessage = stdin.readLine();//ввод текста с клавиатуры System.out.println("you've entered: "+clientMessage);//вывод на консоль //строки и значения строковой переменной while(!clientMessage.equals("quite")) {//выполнение цикла, пока строка //не будет равна "quite" coos.writeObject(clientMessage);//потоку вывода присваивается //значение строковой переменной (передается серверу) System.out.println("~server~: "+cois.readObject());//выводится на //экран содержимое потока ввода (переданное сервером) .out.println("---------------------------");//выводится на //консоль clientMessage = stdin.readLine();//ввод текста с клавиатуры System.out.println("you've entered: "+clientMessage);//вывод на //консоль строки и значения строкой переменной } coos.close();//закрытие потока вывода cois.close();//закрытие потока ввода clientSocket.close();//закрытие сокетного соединения }catch(Exception e) {//обработка исключения типа Exception e.printStackTrace();//выполнение метода исключения е } } } Для того чтобы программа заработала, надо оба исходных текста с расширением .java открыть, скажем, в JCreator’е, причем в одном окне, откомпилировать и запустить сначала сервер, затем клиент. В результате проделанной работы на экране появится консольное окно сервера и клиента:   Теперь введем в окно клиента какую-либо строку:   Как видим, сначала строка отразилась в клиентском окне, затем сервер вывел полученную им строку в своем окне, затем клиент вывел строку, переданную сервером, и ожидает ввода новой строки. Теперь введем слово «quite». Программа завершила свою работу. Сначала закрылось окно клиента, затем – окно сервера. |