Лекции / РАЗРАБОТКА ПРИЛОЖЕНИЯ С КЛИЕНТ-СЕРВЕРНОЙ АРХИТЕКТУРОЙ
.pdf
|
|
95 |
|
m = SerializeAndDeserialize.Serialize(cm); |
Сериализованное значение объекта cm |
|
|||||
|
|
|
присваиваем переменной m |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
responseData = m.Data; |
|
|
|
В массив responseData копируем содержимое |
|
||
|
|
|
|
|
|
массива Data объекта m |
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
Stream.Write(responseData, 0, |
|
|
Отправляем массив байтов responseData |
|
|||
|
|
|
|
|
responseData.Length); |
|
|
|
клиенту |
|
|
|
|
98 |
|
label: |
|
|
|
|
|
|
|
|
|
99 |
|
responseData = null; |
|
|
|
Обнуление массива responseData |
|
||
|
|
100 |
}}}}} |
|
|
|
|
|
|
||
|
|
|
|
|
Таким образом, разделяются сущность подключенного клиента и сущность сервера. Теперь надо запустить |
|
|||||
|
|
прослушивание в основном классе программы. |
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
Листинг 24.12 – Запуск работы сервера |
|
|
|
|
|
|
|
|
|
||||
|
1 |
|
public partial class Form1 : Form |
|
|
|
|
||||
|
2 |
|
{ |
|
|
|
|
|
|
|
|
|
3 |
|
ServerObject server; |
|
|
|
|
Создание объекта сервера |
|
||
|
4 |
|
static Thread listenThread; |
|
|
|
Объявление потока для прослушивания запросов |
|
|||
|
5 |
|
public Form1() |
|
|
|
|
|
|
||
|
6 |
|
{ |
|
|
|
|
|
|
|
|
|
7 |
|
InitializeComponent(); |
|
|
|
|
|
|||
|
8 |
|
server = new ServerObject(); |
|
|
|
|
|
|||
|
9 |
|
listenThread |
= |
new |
Thread(new |
|
Создание потока и прикрепление к нему метода |
|
||
|
|
ThreadStart(server.Listen)); |
|
|
|
прослушивания Listen класса ServerObject |
|
||||
|
10 |
|
listenThread.Start();}} |
|
|
|
Запуск потока listenThread |
|
21
4. Клиентская часть приложения
Рассмотрим реализацию клиентской части приложения.
В качестве клиентской части приложения видоизменим проект десктопного приложения с предыдущей лабораторной работы.
Начнем с изменения процесса регистрации. При регистрации данные, введенные в текстовые поля пользователем, передаются как инициализирующие значения свойств объекта класса User и Student (если выбрана регистрация студента) или Professor
(если выбрана регистрация преподавателя). Далее созданные объекты сериализуются и отправляются для дальнейшей обработки серверу.
Схема передачи и приема сериализованных объектов от клиента серверу при регистрации студента представлена на рисунке 24.7.
Рисунок 24.7 – Схема передачи сериализованных объектов
Модифицированная версия процесса регистрации представлена в листинге 24.13.
|
|
|
Листинг 24.13 Регистрация пользователя |
|
|
|
|
|
|
|
1 |
public partial class FormReg : Form |
Класс формы регистрации |
|
|
2 |
{ |
|
|
|
3 |
private Form1 Form1; |
Экземпляр класса формы авторизации |
|
|
4 |
private byte[] imageBytes; |
Массив байтов для хранения фотографии |
|
|
пользователя |
|
||
|
|
|
|
|
|
|
|
Объект TCP-клиента. В конструктор класса |
|
|
5 |
private TcpClient client = new |
TcpClient передается физический IP-адрес |
|
|
TcpClient("127.0.0.1", 8888); |
("127.0.0.1") расположения сервера и номер порта |
|
|
|
|
|
||
|
|
|
(8888), по которому происходит подключение. |
|
|
6 |
private Byte[] data; |
Массив байтов для хранения данных, передаваемых от |
|
|
клиента к серверу |
|
||
|
|
|
|
|
|
7 |
private NetworkStream stream; |
Поток, используемый для взаимодействия с сервером |
|
|
8 |
private MyLib.Message m1, m2, m; |
Экземпляры класса Message из библиотеки MyLib, |
|
|
9 |
private ComplexMessage cm = new |
|
|
|
созданной на предыдущем этапе |
|
||
|
ComplexMessage(); |
|
||
|
|
|
|
|
|
10 |
public FormReg(Form1 form1) |
Конструктор класса формы регистрации |
|
|
11 |
{ |
|
|
|
12 |
InitializeComponent(); |
|
|
|
13 |
this.Form1 = form1; |
Инициализация свойства, определенного в строке 3 |
|
|
14 |
this.stream = client.GetStream(); |
Инициализация потока, определенного в строке 7 |
|
|
15 |
} |
|
|
|
|
|
Метод, инициализирующий элементы отправляемого |
|
|
16 |
private void InitComponentMessage(object |
серверу пакета данных. Здесь first – первый элемент |
|
|
first, object second, int status) |
пакета, second – второй элемент пакета, status – |
|
|
|
|
|
номер статуса, определяющий тип запроса. |
|
|
17 |
{ |
|
|
|
18 |
this.m1 = |
Инициализация объекта m1 значением, полученным |
|
|
SerializeAndDeserialize.Serialize(first); |
после сериализации объекта first |
|
|
19 |
this.m2 = |
Инициализация объекта m2 значением, полученным |
|
|
SerializeAndDeserialize.Serialize(second); |
после сериализации объекта second |
|
|
|
20 |
cm.First = m1; |
Присваивание свойству First объекта cm ссылки на |
|
|
объект m1 |
|
||
|
|
|
|
|
|
21 |
cm.Second = m2; |
Присваивание свойству Second объекта cm ссылки на |
|
|
объект m2 |
|
||
|
|
|
|
|
|
22 |
cm.NumberStatus = status; |
Инициализация статуса запроса |
|
|
23 |
m = SerializeAndDeserialize.Serialize(cm); |
Инициализация объекта m значением, полученным |
|
|
после сериализации объекта cm |
|
||
|
|
|
|
|
|
24 |
this.data = m.Data; |
Инициализация массива байтов data ссылкой на |
|
|
свойство Data объекта m |
|
||
|
|
|
|
|
|
25 |
} |
|
|
|
26 |
private void buttonReg_Click(object |
Метод обработчик нажатия на кнопку |
|
|
sender, EventArgs e) |
«Зарегистрироваться» |
|
|
|
27 |
{ |
|
|
|
28 |
if (comboBoxRole.SelectedItem.ToString() |
Если при заполнении текстовых полей в качестве роли |
|
|
== "Студент") |
в comboBoxRole указан «Студент» |
|
29{
Student student = new Student() { Name = textBoxFIO.Text, NumberGroup =
|
|
|
int.Parse(textBoxNumGroup.Text), |
|
Создается объект student и инициализируются все |
|
|
30 |
|
PersonalData = |
|
его свойства согласно значениям, введенным в |
|
|
|
|
richTextBoxPersonalData.Text, Photo = |
|
соответствующие текстовые поля. |
|
|
|
|
this.imageBytes, Specialty = "Программист" |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
User user = new User() { Student = |
|
Создается объект user и инициализируются все его |
|
|
|
|
student, Login = textBoxLogin.Text, |
|
|
|
|
31 |
|
|
свойства согласно значениям, введенным в |
|
|
|
|
Password = textBoxPassword.Text, Role = |
|
|
||
|
|
|
(string)comboBoxRole.SelectedItem }; |
|
соответствующие текстовые поля. |
|
|
|
|
|
|
|
|
|
|
24 |
|
|
|
Вызов метода InitComponentMessage и передача в
32 this.InitComponentMessage(student,0); user, него в качестве параметра first – объекта student, second – объекта user, status – цифры 0.
33}
else if
34(comboBoxRole.SelectedItem.ToString() == "Преподаватель")
35{
Professor professor = new Professor() { Name = textBoxFIO.Text, Position =
36textBoxNumGroup.Text, PersonalData = richTextBoxPersonalData.Text, Photo = this.imageBytes };
User user = new User() { Professor = professor, Login = textBoxLogin.Text,
37Password = textBoxPassword.Text, Role = (string)comboBoxRole.SelectedItem };
38this.InitComponentMessage(professor,0); user,
39}
Если при заполнении текстовых полей в качестве роли в comboBoxRole указан «Преподаватель»
Создается объект professor и инициализируются все его свойства согласно значениям, введенным в
соответствующие текстовые поля.
Создается объект user и инициализируются все его свойства согласно значениям, введенным в
соответствующие текстовые поля.
Вызов метода InitComponentMessage и передача в него в качестве параметра first – объекта student, second – объекта user, status – цифры 0.
|
40 |
stream.Write(data, 0, data.Length); |
Отправляем массив байтов data серверу |
41 |
stream.Flush(); |
Очистка содержимого потока stream |
42}
43…
44}
25
26
При авторизации данные, введенные в текстовые поля пользователем, передаются серверу для дальнейшего сравнения на равенство со значениями свойства логина и пароля пользователя из базы данных. Далее, если нашлось совпадение логина и пароля в базе данных, в сервере создается объект User, он сериализуются и отправляются для дальнейшей обработки клиенту.
Модифицированная версия процесса авторизации представлена в листинге 24.14.
|
Листинг 24.14 – Класс формы авторизации |
|
|
|
|
1 |
public partial class Form1 : Form |
|
2 |
{ |
|
3 |
FormReg FormReg; |
|
4 |
FormStudentAccount FormStudentAccount; |
|
5 |
FormReference FormReference; |
|
6 |
FormProfessorAccount FormProfessorAccount; |
|
7 |
TcpClient client = new TcpClient("127.0.0.1", 8888); |
|
8 |
Byte[] data; |
|
9 |
NetworkStream stream; |
|
10 |
MyLib.Message m, m1, m2; |
|
11 |
ComplexMessage cm = new ComplexMessage(); |
|
12 |
public Form1() |
|
13 |
{ |
|
14 |
InitializeComponent(); |
|
15 |
this.stream = client.GetStream(); |
|
16 |
} |
|
17 |
private void buttonAuth_Click(object sender, EventArgs e) |
|
18 |
{ |
|
|
this.m1 = |
|
19 |
SerializeAndDeserialize.Serialize(textBoxLogin.Text); |
|
//Сериализация логина, введенного в текстовое поле |
|
|
|
textBoxLogin |
|
|
this.m2 = |
|
20 |
SerializeAndDeserialize.Serialize(textBoxPassword.Text); |
|
//Сериализация пароля, введенного в текстовое поле |
|
|
|
textBoxPassword |
|
21 |
this.cm.First = this.m1; //«Упаковка» сообщения m1 с |
|
логином в пакет cm |
|
|
22 |
this.cm.Second = this.m2; //«Упаковка» сообщения m2 с |
|
паролем в пакет cm |
|
|
23 |
this.cm.NumberStatus = 1; //«Упаковка» типа запроса (1 – |
|
|
запрос на авторизацию) NumberStatus в пакет cm |
|
24 |
this.m = SerializeAndDeserialize.Serialize(this.cm); |
//Сериализация пакета с дальнейшей упаковкой в объект m |
|
25 |
data = this.m.Data; //Передача массива байтов Data из |
объекта m в массив data |
|
26 |
stream.Write(data, 0, data.Length); //Отправка массива |
|
байтов data серверу |
27 |
if (stream.CanRead) //Если поток доступен для чтения |
28 |
{ |
29 |
int numberOfBytesRead = 0; |
30 |
byte[] readingData = new byte[6297630]; |
31 |
do |
32 |
{ |
|
numberOfBytesRead = stream.Read(readingData, 0, |
33 |
readingData.Length); //Считываем данные, полученные от |
|
сервера, в массив байтов readingData |
34 |
} |
35 |
while (stream.DataAvailable); |
36 |
this.m.Data = readingData; |
|
this.cm = |
37 |
(ComplexMessage)SerializeAndDeserialize.Deserialize(m); |
|
//Поэтапно десериализуем массив байтов для восстановления |
|
объектов из полученного пакета |
38 |
if (cm.NumberStatus == 2) //Если статус запроса «Успешная |
|
авторизация» |
39 |
{ |
40 |
ComplexMessage complexMessage = (ComplexMessage) |
|
SerializeAndDeserialize.Deserialize(m); |
41 |
User user1 = (User) |
SerializeAndDeserialize.Deserialize(complexMessage.First); |
|
42 |
Professor professor; |
43 |
Student student = (Student) |
SerializeAndDeserialize.Deserialize(complexMessage.Second); |
|
44 |
if (user1.Role == "Студент") |
45 |
{ |
46 |
user1.Student = student; |
|
this.FormStudentAccount = new FormStudentAccount(this, |
47 |
user1); //Создаем экземпляр формы личной страницы студента |
|
и заполняем её содержимое |
48 |
this.FormStudentAccount.Show(); |
49 |
this.FormStudentAccount.Text = "Профиль " + |
|
user1.Student.Name; |
|
28 |
50 |
this.FormStudentAccount.labelStudentName.Text = "Добро |
пожаловать, " + user1.Student.Name; |
|
51 |
this.FormStudentAccount.Visible = true; |
52 |
this.Visible = false; |
53 |
return; |
54 |
} |
55 |
else if (user1.Role == "Преподаватель") |
56 |
{ |
57 |
professor = user1.Professor; |
58 |
this.FormProfessorAccount = new FormProfessorAccount(this, |
|
user1, user1.Professor); |
59 |
this.FormProfessorAccount.Text = "Профиль " + |
user1.Professor.Name; |
|
60 |
this.FormProfessorAccount.labelProfessorName.Text = "Добро |
пожаловать, " + user1.Professor.Name; |
|
61 |
this.FormProfessorAccount.Visible = true; |
62 |
this.Visible = false; |
63 |
return; |
64 |
} |
65 |
} |
66 |
else if (cm.NumberStatus == 3) //Если статус запроса |
|
«Ошибка авторизации» |
67 |
{ |
68 |
MessageBox.Show("Неверный логин или пароль"); |
69 |
} |
70 |
} |
71 |
} |
|
5. Создание и форматирование DOCX файла |
DocX1 - это библиотека .NET, которая позволяет разработчикам легко и интуитивно управлять файлами Microsoft Word. Библиотеку DocX можно добавить в проект при помощи установщика пакетов NuGet.
1 С другими методами библиотеки DocX можно ознакомиться на сайте https://progtask.ru/rabota-s-word-pri-pomoshi-c-sharp/
29
Рисунок 24.8
Предположим, что разрабатываемое приложения должно создавать заполненное задание на дипломный проект для согласования темы. Часть документа, которая будет генерироваться программой с использованием библиотеки DocX, представлена на рисунке 24.9.
Рисунок 24.9 – Генерируемый документ
Документ условно делится на параграфы, представляющие собой абзацы с
элементами наполнения (текстом, таблицами, ссылками, изображениями и т.д.). DocX 30