Файл: Лабораторная работа Разработка абстрактного базового класса 3 Лабораторная работа Параллелизм и потоки 7.docx
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 08.11.2023
Просмотров: 48
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ
РОССИЙСКОЙ ФЕДЕРАЦИИ
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ
ВЫСШЕГО ОБРАЗОВАНИЯ
«НОВОСИБИРСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ»
КАФЕДРА ВЫЧИСЛИТЕЛЬНОЙ ТЕХНИКИ
Лабораторные работы № 2-6
ПО ДИСЦИПЛИНЕ «Разработка клиент-серверных приложений»
Факультет: ИДО Преподаватель: Романов Е.Л.
Группа: ДТ-960
Студенты:
Ангальд В.В
Достов А.Е.
Григорьев М.Ю.
Гирько В.В.
Новосибирск 2023 г.
Contents
Лабораторная работа 2. Разработка абстрактного базового класса 3
Лабораторная работа 3. Параллелизм и потоки 7
Лабораторная работа 4. Работа с файлами 9
Лабораторная работа 5. Сетевое соединение на сокетах 12
Лабораторная работа 6. Передача данных без установления соединения 14
Лабораторная работа 2. Разработка абстрактного базового класса
Цель работы:
Разработать абстрактный базовый класс графического объекта с данными и функционалом (абстрактными и переопределяемыми методами): координаты центра и размеры охватывающего прямоугольника, цвет, рисование объекта, проверка на принадлежность точки объекту, запись/чтение в различные потоки, а также все остальные, необходимые для реализации функционала в последующих работах.
Разработать производный класс смайлик. Разработать оконное приложение с созданием объектов по координатам клика мыши.
Объекты сохраняются в векторе в виде ссылок на базовый класс.
Ход работы:
Для разработки класса графического объекта за основу был взят класс GrObject.
public abstract class GrObject implements Runnable, Serializable{
double x,y,dx,dy; // Координаты фигуры, изменения координат
double V0=0.7; // скорость изменения координат
transient Color cl; // цвет объекта
transient int maxx,maxy; // максимальные значения координат
transient volatile boolean stop=false;
transient volatile boolean pause=false;
transient Graphics gg;
transient Component pp;
public GrObject() // конструктор по умолчанию
public GrObject(Component p0) // конструктор с параметрами
public void setComponent(Component p0) // инициализирует параметры объекта
void Save(DataOutputStream F) throws IOException // записывает в поток координаты объекта, их смещения и цвет
void Load(DataInputStream F) throws IOException //
считывает из потока координаты объекта, их смещения и цвет
void SaveText(BufferedWriter F) throws IOException // выводит в поток координаты объекта, их смещения и цвет в виде текста
void LoadText(BufferedReader F) throws IOException // считывает из потока координаты объекта, их смещения и цвет
abstract void step() // метод анимации объекта
double size() // возвращает размер объекта
boolean inside(int xx,int yy) // проверка расположения координат внутри объекта
public void paint(boolean fore) // задаёт цвет объекта
public void run() // отрисовывает объект
public String toString()// конвертация данных в строку
public static void setXMLParser(XStream xstream) // сериализует параметры объекта
}
Унаследуем этот класс в нашем дочернем классе и перегрузим основные методы:
public class Smile extends GrObject {
double R,R0; // диаметр и начальный диаметр смайла
float margin = 0.2f;
double V00=0.05;
int ns = 1; // шаг изменения диаметра смайла
public Smile(){} // конструктор по умолчанию
public Smile(double r0,Component p0) // конструктор с параметрами
@Override
public double size() // возвращает радиус смайла
public Smile(int xx,int yy,double r0,Component p0) // конструктор с параметрами
@Override
public void paint(boolean fore) // метод отрисовки смайла
@Override
public void step() // изменяет радиус смайла
@Override
public boolean inside(int xx,int yy) // проверка расположения координат внутри смайла
public void Save(DataOutputStream F) throws IOException // записывает в поток координаты и радиус смайла
public void Load(DataInputStream F) throws IOException // считывает из потока координаты и радиус смайла
public void LoadText(BufferedReader F) throws IOException // считывает из потока координаты и радиус смайла в виде текста
public void SaveText(BufferedWriter F) throws IOException // выводит в поток координаты и радиус смайла в виде текста
public static void setXMLParser(XStream xstream) // сериализует параметры смайла
public void setComponent(Component p0) // инициализирует параметры объекта
public String toString({ // конвертация данных в строку
Полный код созданного класса расположен в приложении 1.
Добавим выбор созданного класса объектов в интерфейс:
public MainWindow() {
initComponents();
TYPE.add("Circle");
TYPE.add("Star");
TYPE.add("Smile");
this.setBounds(300,200,575,425);
}
private void TXTMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_TXTMouseClicked
int xx=evt.getX();
int yy=evt.getY();
GrObject pp;
switch (evt.getButton()){
case 1:
if (TYPE.getSelectedIndex()==0)
pp=new Circle(xx,yy,70,TXT);
else if (TYPE.getSelectedIndex()==1)
pp=new Zwezda(xx,yy,70,6,TXT);
else
pp=new Smile(xx,yy,70,TXT);
OBJ.add(pp);
new Thread(pp).start();
break;
case 3:
int nn=OBJ.size();
for (int i=0;i
if (pp.inside(xx, yy)) {
pp.stop=true;
OBJ.remove(i);
break;
}}
case 2:
int n2=OBJ.size();
for (int i=0;i
if (pp.inside(xx, yy)) {
if (conn!=null)
conn.mesPutObject(pp);
//pp.pause=true;
break;
}}
break;
}
}
Проверка работы созданного класса:
Рис. 1 – Диалоговое окно выбора объекта
Рис. 2 – Результат отрисовки объекта
Лабораторная работа 3. Параллелизм и потоки
Цель работы:
Реализовать процесс движения объекта (Триангулярная пульсация размера фигуры), остановки и возобновления движения по отдельности и всех вместе. Внести в базовый класс функционал движения, в производный – алгоритм движения для конкретного типа.
Ход работы:
Реализован метод run(), который перемещает будет обеспечивать равномерное движение со случайным направлением и скоростью, отскакивание от
краев экрана.
public void run(){ // отрисовывает объект
while(!stop){
try {
Thread.sleep(10);
synchronized (pp){
if (pause){
pause=false;
pp.wait();
}
paint(true);
step();
x+=dx;
y+=dy;
double sz=size();
if (dx>0 && x+sz>maxx || dx<0 && x
}
} catch (InterruptedException ex) {}
}
paint(true);
}
Также реализуем алгоритм изменения размера в методе step():
@Override
public void step(){ // изменяет радиус смайла
if (R > 100 || R < 50)
ns = -ns;
R+= ns;
}
В данном методе радиус смайла с каждым тиком будет увеличиваться на единицу, пока не достигнет верхней границы (100), после чего начнет уменьшаться до достижения нижней границы (50), после чего цикл начнется вновь.
Поскольку в методе run() происходит вызов метода step(), при каждом тике смайл будет равномерно перемещаться и изменяться в размере. Пример такого движения продемонстрирован на рисунках 3 и 4.
Рис. 3 – Первоначальная позиция объекта
Рис. 4 – Позиция объекта после изменения размера и перемещения
Лабораторная работа 4. Работа с файлами
Цель работы:
К разделу 2.1. В базовом классе реализовать (объявить) методы (абстрактные) чтения/записи объекта в двоичный и текстовый потоки. Переопределить во всех производных классах. В оконном классе реализовать методы сохранения и загрузки вектора объектов в тестовый, двоичный и сериализуемый файл (двоичная сериализация средствами Java и XML-сериализация с использованием библиотеки xstream). Формат двоичного и текстового файла содержит начальный счетчик объектов, а затем для каждого их них – имя и содержимое. При загрузке из файла создавать объект файла произвольного класса с помощью средств рефлексии (методы Class.forName и Class.newInstance)
Ход работы:
В ходе выполнения релизованы чтение/запись объектов в следующие типы
потоков:
- символьный поток данных (классы FileReader и FileWriter);
- бинарный поток объектов (классы ObjectInputStream и ObjectOutputStream);
- файловый поток для работы с XML-файлами (классы FileOutputStream и
FileInputStream).
Тестовый набор представлен на рис.5. По заданию это объекты, которые
Размещаются в заданных координатах и вписываются в заданный прямоугольник.
Рис. 5 – тестовый набор
Рис. 6 – окно выбора файла для записи
Рис. 7 – запись в текстовый файл
Рис. 8 – запись потока объектов в бинарный файл
Рис. 9 – запись в XML-файл
Если сравнить содержимое файлов txt и xml, то можно увидеть, что в них
хранятся идентичные объекты.
Для корректной работы файлов обновляем библиотеки gson и xstream
Рис. 10 – обновление библиотек
Лабораторная работа 5. Сетевое соединение на сокетах
Цель работы:
К разделу 2.3. Разработать приложение с клиентской и серверной частью. Серверная часть реализуется в потоке и запускается/останавливается при помощи флажка. Серверная компонента ждет запроса на соединение на фиксированном порте. Клиентская компонента в другой программе запрашивает соединение с серверной. Протокол является симметричным (двунаправленным), т.е. каждое приложение может посылать один тот же набор команд: закрытие соединения, очистка вектора объектов, передача сериализованного объекта, запрос размера вектора объектов, запрос объекта с заданным номером из вектора. Принимаемые объекты отображаются в клиенте и запоминаются в векторе.
Ход работы:
class Utis
Методы:
static void synch (Runnable code) - синхронизация в GUI
classTCPDriver - реализует интерфейс LineDriver
void open (Stringip, intport, booleanserver, finalLineAnswerback) - открывает
соединение с сервером (если booleanserver == false) или ожидает подключение
клиента (если booleanserver == true) . Создаёт два потока для входящих и
исходящих данных.
void close() - закрывает соединение
void sendData(byte[] data) - отправляет данные
byte[] recData() - принимает данные
class TCPConnect - - реализует интерфейс NetDriver
переменные:
public final static int mClear=1;
public final static int mSendSize=2;
public final static int mGetSize=3;
public final static int mGetObject=4;
public final static int mRemObject=5;
public final static int mPutObject=6;
public final static int mGetObjectList=7;
public final static int mPutObjectList=8;
Благодаря модификатору final, эти переменные нельзя переопределить.
методы:
void mesClear() - с помощью LineDriver отправляет переменную mClear
void mesGetSize() - с помощью LineDriver отправляет переменную mGetSize
void mesSendSize(int size) - с помощью LineDriver отправляет переменную
mSendSize и size
void mesGetObject(int idx) - с помощью LineDriver отправляет переменную
mGetObject и idx
void mesRemObject(int idx) - с помощью LineDriver отправляет переменную
mRemObject и idx
void mesPutObject(GrObject pp) - с помощью LineDriver отправляет объект
класса GrObject
void mesGetObjectList() - с помощью LineDriver отправляет переменную
mGetObjectList()
void mesPutObjectList(ArrayList
отправляет массив объектов и его размерность.
void open(String ip, int port, boolean server, LineDriver line0, NetAnswer
back0) - с помощью LineDriver открывает соединение
void close() - с помощью LineDriver закрывает соединение
void run() - получает с помощью LineDriver одну из, перечисленных выше,
переменных класса. В зависимости от переменной, которую получил, выполняет
соответствующие действия и производит синхронизацию в GUI до тех пор, пока
shutdown == 0
Лабораторная работа 6. Передача данных без установления соединения
Цель работы:
К разделу 3.1. Задание в л.р.5 реализовать с использованием класса дейтаграмм протокола UDP без установления соединения (класс DatagramSocket). Флажком выделяется «первое/второе» приложение, отличающиеся только номером порта, на котором они прослушивают прием. Например, первое принимает данные на порте 7001, а передает на 7002, второе – наоборот. Для конвертации XML-строки, содержащей передаваемый объект, в массив байтов для передачи в дейтаграммный сокет использовать классы ByteArrayOutputStream/ByteArrayOutputStream в качестве классаисточника текстового потока.
Ход работы:
classUDPDriver - реализует интерфейс LineDriver
методы:
voidclose() - закрыть соединение
voidsendData(byte[] data) – отправляет данные
byte[] recData() - принимает данные в буфер
void open(String ip0, int port, boolean server, LineAnswer back) – открывает
соединение
Окно приложения содержит следующие компоненты:
-
Строка меню, в котором содержится элемент файл, при раскрытии которого -
отображаются доступные форматы для сохранения или загрузки данных; -
Список доступных графических объектов, поля для ввода размера объекта; -
Строка состояния (отображает состояние и параметры, передаваемые по сети); -
Элементы управления сетевым подключением; -
Элемент для рисования графических объектов.
Чтобы добавить новый графический объект нужно выбирать тип фигуры (круг или звезда) и размер (диаметр), затем левой кнопки мыши щелкнуть в области рисования. Цвет объекта генерируется случайным образом, добавленные равномерное движение со случайным направлением и скоростью с отскакиванием от краев экрана.
Чтобы удалить графический объект нужно по нему щелкнуть правой кнопкой мыши.
Для демонстрации работы программы по сети необходимо запустить два
экземпляра, один из которых будет первым абонентом, а другой – вторым абонентом.
Установление порядка подключения осуществляется при помощи флажка Server.
Сначала запускается первый экземпляр программы, в нем устанавливается на
форме флажок Server и нажимается кнопка Connect. В этом случае запускается поток
обработки сообщений, в котором первый порт будет принимать сообщения, а во второй –
будут уходить ответные сообщения. По умолчанию соединение устанавливается по
TCPпротоколу. Сообщения, которыми ведется обмен – это поток двоичных данных, в
котором содержится код команды и опционально контент, в качестве которого может
выступать:
-
Целое число, метод mesPutSize или mesGetSize; -
Имя класса объекта и поля графического объекта в двоичном формате, метод mesPutSize или mesGetObject.
При нажатии средней кнопки мыши (колеса) объект
отправляется другой программе.
Рис. 11 – пример передачи объектов по TCP протоколу
Чтобы программы обменивались сообщениями по UDPпротоколу, выполняются те же действия, что описаны выше, при установленном флажке UDP. В данном случае флажок Server влияет только на порт, который прослушивает программа.
Рис. 12 – пример передачи объектов по UDP протоколу