Пред.
След.
Макеты страниц
Распознанный текст, спецсимволы и формулы могут содержать ошибки, поэтому с корректным вариантом рекомендуем ознакомиться на отсканированных изображениях учебника выше Также, советуем воспользоваться поиском по сайту, мы уверены, что вы сможете найти больше информации по нужной Вам тематике ДЛЯ СТУДЕНТОВ И ШКОЛЬНИКОВ ЕСТЬ
ZADANIA.TO
3.2. Приложение, реализующее клиент-серверную архитектуру
В данном примере рассматривается упрошенный пример приложения, реализующего клиент-серверные взаимодействия в сети с использованием сокетных соединений. Назначение приложения - обмен текстовыми сообщениями между сервером и клиентом. Переданные сообщения сохраняются в файлах данных, как на стороне сервера, так и на стороне клиента. Обе части приложения имеют похожий графический интерфейс и показаны на рис. 3.1 и рис. 3.2.
Рис. 3.1. Окно сервера
Рис. 3.2. Окно клиента Рассмотрим серверную часть приложения. Выполним импорт необходимых java-пакетов: import java.net.*; //классы для работы с сетью import java.io.*; //классы для взаимодействия с файлами Объявим класс, реализующий сервер следующим образом: public class ServerForm extends java.awt.Frame implements Runnable Класс сервера ServerForm является наследником от стандартного класса Frame и реализует интерфейс Runnable. Реализация интерфейса Runnable необходима, если мы хотим, чтобы класс обеспечивал свою функциональность в параллельно выполняемых подпроцессах. Объявим константу, задающую номер порта, через который будет осуществлятся обмен данными: public final static int PORT = 220; Объявим следующие переменные класса ServerForm: Socket sock = null; //Ссылка на сокетное соединение BufferedReader in = null; //Буферизованный поток ввода FileWriter fw = null; //Файловый поток вывода BufferedWriter out = null;// Буферизованный поток вывода Thread t = new Thread(this); //Новый подпроцесс выполнения Буферизованные потоки BufferedWriter и BufferedReader будем использовать для обмена данными между сервером и клиентом. FileWrite для записи полученных сообщений в файл данных. Для того чтобы отделить процесс чтения данных из сети от основного процесса выполнения серверного приложения, нам потребуется новый подпроцесс. Для этого мы и создали объект t класса Thread. Создадим метод connect(), реализующий сокетное соединение с клиентом. public void connect() { В процессе установления сокетных соединений возможно появление различных исключительных ситуаций. Поэтому защитим код от возможных исключений, добавив оператор try и реализуя блок catch (Exception ex). Создадим серверный сокет и вызовем метод accept() для ожидания соединения со стороны клиента: ServerSocket ss = new ServerSocket(PORT); sock = ss.accept(); Получаем потоки ввода-вывода из созданного сокетного соединения: in = new BufferedReader(new InputStreamReader(sock.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())); Запускаем на исполнение параллельный подпроцесс чтения данных: t.start(); Открываем файл данных, для записи полученных сообщений: fw = new FileWriter("messageServ.txt"); Реализуем метод run() интерфейса Runnable. public void run(){ Объявим строковую переменную, для хранения полученного сообщения: String indata_; В процессе получения данных через поток ввода возможно появление исключительных ситуаций. Поэтому защитим код от возможных исключений, добавив оператор try и реализуя блок catch (Exception ex). Будем читать полученные данные в следующем цикле: while(true){ Запишем полученное сообщение в строку, прочитав его из потока ввода методом readLine(). Данный метод позволяет читать сообщение в виде строки текста, что является несомненным достоинством: indata_ = in.readLine(); Отобразим сообщение в компоненте типа List: list1.add(indata_); Запишем сообщение в файл: fw.write(indata_); Реализуем методы-обработчики события ActionPerformed для компонентов-кнопок «Connect», «Send» и «Close». По щелчку на кнопке «Connect» будет вызван следующий обработчик, в котором производится вызов метода connect(): private void button2ActionPerformed(java.awt.event.ActionEvent evt) { connect(); } По щелчку на кнопке «Send» будет вызван следующий обработчик: private void button1ActionPerformed(java.awt.event.ActionEvent evt) { try { //читаем введенную строку сообщения String data = textField1.getText(); //записывем сообщение в выходной поток out.write(data); out.newLine(); //очищаем буфер out.flush(); } catch(Exception e) {} } По щелчку на кнопке «Close» необходимо будет закрыть соединение, все потоки и файлы, вызвав следующий обработчик: private void button3ActionPerformed(java.awt.event.ActionEvent evt) { // Закрываем файл данных, потоки и соединение try{ fw.close(); in.close(); out.close(); sock.close(); } catch(Exception e) {} } Полный код серверной части приведен в приложении 3. Рассмотрим клиентскую часть приложения. Как и в классе сервера выполним импорт java-такетов: import java.net.*; //классы для работы с сетью import java.io.*; //классы для взаимодействия с файлами Объявим класс, реализующий клиента следующим образом: public class ClientForm extends java.awt.Frame implements Runnable Класс сервера ClientForm также является наследником от стандартного класса Frame и реализует интерфейс Runnable. Объявим следующие переменные класса ClientForm: Socket ss = null; //Ссылка на сокетное соединение BufferedReader in = null; //Буферизованный поток ввода FileWriter fw = null; //Файловый поток вывода BufferedWriter out = null;// Буферизованный поток вывода Буферизованные потоки BufferedWriter и BufferedReader будем использовать для обмена данными между клиентом и сервером. FileWrite для записи полученных сообщений в файл данных. Для того чтобы отделить процесс чтения данных из сети от основного процесса выполнения клиентского приложения, нам потребуется новый подпроцесс. Для этого создадим объект process1 класса Thread. Thread process1 = new Thread(this); //Новый подпроцесс выполнения Создадим метод connect() для установления соединения клиента с сервером. public void connect() { try { //Устанавливаем соединение с локальным хостом InetAddress addr = InetAddress.getLocalHost(); ss = new Socket(addr, 220); //Получаем потоки ввода_вывода in = new BufferedReader(new InputStreamReader(ss.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream())); //Запускаем новый подпроцесс process1.start(); //Открываем файл fw = new FileWriter("messageCli.txt"); } catch(Exception e){ System.out.println("ошибка "); } } Обратите внимание, что в данном примере мы устанавливаем соединение с локальным хостом, получая его Интернет-адрес с помощью метода getLocalHost() класса InetAddress. В случае установления соединения с удаленным хостом, нам потребовалось бы вызвать метод getByName("наименование хоста"). Также обратите внимание, что, мы открываем сокетное соединение по порту с номером 220, именно с тем номером порта, с которым создавали серверный сокет в серверной части приложения. Реализуем метод run() интерфейса Runnable. public void run(){ String s1; //строка для хранения текущего сообщения try{ //В цикле читаем данные из потока while(true){ //записываем данные из потока в строку s1 = in.readLine(); //Отображаем в компоненте List list1.add(s1); //Записываем в файл fw.write(s1); } } catch(Exception e) {} } Реализуем методы-обработчики события ActionPerformed для компонентов-кнопок «Connect», «Send» и «Close». По щелчку на кнопке «Connect» будет вызван следующий обработчик, в котором производится вызов метода connect(): private void button1ActionPerformed(java.awt.event.ActionEvent evt) { connect(); } По щелчку на кнопке «Send» будет вызван следующий обработчик: private void button2ActionPerformed(java.awt.event.ActionEvent evt) { //Получаем строку от пользователя и пересылаем серверу try { String data = textField1.getText(); out.write(data); out.newLine(); out.flush(); } catch(Exception e){} } По щелчку на кнопке «Close» необходимо будет закрыть соединение, все потоки и файлы, вызвав следующий обработчик: private void button3ActionPerformed(java.awt.event.ActionEvent evt) { //Закрываем файл, потоки и соединение try{ fw.close(); in.close(); out.close(); ss.close(); } catch(Exception e) {} } Полный код клиентской части приведен в приложении 2.
|
1 |
Оглавление
|