Лабораторные работы / Методические указания к ЛР по ОАИП (09.02.07)
.pdf
|
19 |
while (true) |
|
|
20 |
{ |
|
|
21 |
if (Stream.CanRead) |
CanRead возвращает значение true, если поток |
|
поддерживает чтение |
||
|
|
|
|
|
22 |
{ |
|
|
23 |
byte[] myReadBuffer = new byte[6297630]; |
Массив байтов для хранения данных, |
|
принимаемых от клиента |
||
|
|
|
|
|
24 |
do |
|
|
25 |
{ |
|
|
26 |
Stream.Read(myReadBuffer, 0, myReadBuffer.Length); |
Запись данных, считанных с потока Stream, в |
|
массив байтов myReadBuffer |
||
|
|
|
|
|
27 |
} |
|
|
28 |
while (Stream.DataAvailable); |
Пока данные есть в потоке Stream |
|
29 |
Student student; |
|
|
30 |
Professor professor; |
|
|
31 |
User user; |
|
|
32 |
MyLib.ComplexMessage complexMessage = new |
|
|
ComplexMessage(); |
|
|
|
33 |
MyLib.Message message = new MyLib.Message(); |
|
|
34 |
message.Data = myReadBuffer; |
Запись принятого пакета данных с клиента в |
|
свойство Data объекта message |
||
|
|
|
|
|
35 |
complexMessage = (ComplexMessage) |
Десериализация полученного пакета message в |
|
SerializeAndDeserialize.Deserialize(message); |
объект complexMessage |
|
|
|
|
|
|
36 |
if (complexMessage.NumberStatus == 0) |
Если NumberStatus, сообщающий о типе |
|
запроса, равен 0 |
||
|
|
|
|
|
37 |
{ |
…то выполняется запрос на добавление нового |
|
пользователя в базу данных |
||
|
|
|
261
|
38 |
try |
|
|
39 |
{ |
|
|
|
student = (Student)SerializeAndDeserialize. |
Десериализуется свойство First сложного |
|
40 |
пакета complexMessage и результат |
|
|
Deserialize(complexMessage.First); |
||
|
|
|
записывается в переменную student |
|
41 |
} |
|
|
42 |
catch |
|
|
43 |
{ |
|
|
|
|
Если в строке 40 произойдет ошибка при |
|
44 |
student = null; |
преобразовании типов, то переменной student |
|
|
|
присвоится нулевой объект null |
|
45 |
} |
|
|
46 |
try |
|
|
47 |
{ |
|
|
|
professor = (Professor)SerializeAndDeserialize. |
Десериализуется свойство First сложного |
|
48 |
пакета complexMessage и результат |
|
|
Deserialize(complexMessage.First); |
||
|
|
|
записывается в переменную professor |
|
49 |
} |
|
|
50 |
catch |
|
|
51 |
{ |
|
|
|
|
Если в строке 48 произойдет ошибка при |
|
52 |
professor = null; |
преобразовании типов, то переменной student |
|
|
|
присвоится нулевой объект null |
|
53 |
} |
|
|
|
user = (User)SerializeAndDeserialize. |
Десериализуется свойство Second сложного |
|
54 |
пакета complexMessage и результат |
|
|
Deserialize(complexMessage.Second); |
||
|
|
|
записывается в переменную user |
262
|
55 |
using (EntityModelContainer db = new |
Создается экземпляр контекста данных для |
|
|
EntityModelContainer()) |
взаимодействия с базой данных |
|
|
|
56 |
{ |
|
|
|
|
|
Обращение к коллекции UserSet для добавления |
|
|
57 |
db.UserSet.Add(user); |
нового объекта user в таблицу UserSet базы |
|
|
|
|
данных |
|
|
58 |
db.SaveChanges(); |
Сохранение изменений, применяемых к базе |
|
|
данных |
|
||
|
|
|
|
|
|
59 |
} |
|
|
|
60 |
} |
|
|
|
|
|
|
|
|
61 |
else if (complexMessage.NumberStatus == 1) |
Если NumberStatus, сообщающий о типе |
|
|
запроса, равен 1 |
|
||
|
|
|
|
|
|
62 |
{ |
…то выполняется запрос на авторизацию |
|
|
пользователя |
|
||
|
|
|
|
|
|
63 |
using (EntityModelContainer db = new |
Создается экземпляр контекста данных для |
|
|
|
EntityModelContainer()) |
взаимодействия с базой данных |
|
|
64 |
{ |
|
|
|
65 |
byte[] responseData; |
Массив байтов для хранения ответа, |
|
|
формируемого сервером на запрос клиента |
|
||
|
|
|
|
|
|
66 |
for (int i = 0; i < db.UserSet.ToList().Count; |
Циклический перебор всех пользователей из |
|
|
i++) |
таблицы UserSet |
|
|
|
67 |
{ |
|
|
|
|
if (db.UserSet.ToList()[i].Login == |
Условие проверки соответствия логина и пароля |
|
|
|
Convert.ToString(SerializeAndDeserialize. |
|
|
|
|
i-го пользователя из коллекции –UserSet логину |
|
|
|
68 |
Deserialize(complexMessage.First)) && |
|
|
|
и паролю, полученными в результате запроса от |
|
||
|
|
db.UserSet.ToList()[i].Password == |
|
|
|
|
клиента |
|
|
|
|
Convert.ToString(SerializeAndDeserialize. |
|
|
|
|
|
|
263
|
|
Deserialize(complexMessage.Second))) |
|
|
69 |
{ |
|
|
|
|
Создаем объект user1 и копируем в него i-й |
|
70 |
User user1 = db.UserSet.ToList()[i]; |
элемент коллекции UserSet, для которого |
|
|
|
выполнилось условие в строке 68 |
|
|
|
Создаем объект user2, вызываем для него |
|
|
|
конструктор по умолчанию и инициализируем |
|
71 |
User user2 = new User() { Login = user1.Login, |
его свойства, скопировав значения свойств |
|
|
Password = user1.Password, Role = user1.Role }; |
объекта user1. Данное действие необходимо для |
|
|
|
дальнейшей корректной десериализации объекта |
|
|
|
класса User со стороны клиента. |
|
72 |
m1 = SerializeAndDeserialize.Serialize(user2); |
Сохранение в переменную m1 сериализованного |
|
значения объекта user2 |
||
|
|
|
|
|
73 |
if (db.UserSet.ToList()[i].Role == "Студент") |
Если роль пользователя – студент |
|
74 |
{ |
|
|
|
|
Создаем объект student1 и копируем в него |
|
75 |
Student student1 = db.UserSet.ToList()[i].Student; |
значение свойства Student i-го элемента |
|
коллекции UserSet, для которого выполнилось |
||
|
|
|
|
|
|
|
условие в строке 73 |
|
|
|
Создаем объект student2, вызываем для него |
|
|
Student student2 = new Student() { Name = |
конструктор по умолчанию и инициализируем |
|
76 |
student1.Name, NumberGroup = student1.NumberGroup, |
его свойства, скопировав значения свойств |
|
|
PersonalData = student1.PersonalData, Photo = |
объекта student1. Данное действие необходимо |
|
|
student1.Photo, Specialty = student1.Specialty }; |
для дальнейшей корректной десериализации |
|
|
|
объекта класса Student со стороны клиента. |
|
77 |
m2 = SerializeAndDeserialize.Serialize(student2); |
Сохранение в переменную m2 сериализованного |
|
значения объекта student2 |
||
|
|
|
264
|
78 |
} |
|
|
79 |
else if (db.UserSet.ToList()[i].Role == |
Если роль пользователя – преподаватель |
|
"Преподаватель") |
|
|
|
80 |
{ |
|
|
81 |
Professor professor1 = |
|
|
db.UserSet.ToList()[i].Professor; |
Повторяем действия, аналогичные строкам 75-77, |
|
|
82 |
Professor professor2 = professor1; |
|
|
но только для объектов класса Professor |
||
|
83 |
m2 = |
|
|
|
||
|
|
SerializeAndDeserialize.Serialize(professor1); |
|
|
84 |
} |
|
|
85 |
cm.First = m1; |
Свойству First объекта cm присваиваем m1 |
|
86 |
cm.Second = m2; |
Свойству Second объекта cm присваиваем m2 |
|
|
|
Свойству NumberStatus объекта cm |
|
87 |
cm.NumberStatus = 2; |
присваиваем значение 2 (статус успешной |
|
|
|
авторизации) |
|
88 |
m = SerializeAndDeserialize.Serialize(cm); |
Сериализованное значение объекта cm |
|
присваиваем переменной m |
||
|
|
|
|
|
89 |
responseData = m.Data; |
В массив responseData копируем содержимое |
|
массива Data объекта m |
||
|
|
|
|
|
90 |
Stream.Write(responseData, 0, |
Отправляем массив байтов responseData |
|
|
responseData.Length); |
клиенту |
|
91 |
goto label; |
Прыжок к label (строка 98) |
|
92 |
} |
|
|
93 |
} |
|
|
|
|
|
|
|
|
Свойству NumberStatus объекта cm |
|
94 |
cm.NumberStatus = 3; |
присваиваем значение 3 (статус неудачной |
|
|
|
авторизации) |
265
|
|
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 |
}}}}} |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Таким образом, разделяются сущность подключенного клиента и сущность сервера. Теперь надо запустить |
|
|||||
|
|
прослушивание в основном классе программы. |
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
Листинг 15.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 |
|
266
4. Клиентская часть приложения
Рассмотрим реализацию клиентской части приложения.
В качестве клиентской части приложения видоизменим проект десктопного приложения с предыдущей лабораторной работы.
Начнем с изменения процесса регистрации. При регистрации данные, введенные в текстовые поля пользователем, передаются как инициализирующие значения свойств объекта класса User и Student (если выбрана регистрация студента) или Professor
(если выбрана регистрация преподавателя). Далее созданные объекты сериализуются и отправляются для дальнейшей обработки серверу.
Схема передачи и приема сериализованных объектов от клиента серверу при регистрации студента представлена на рисунке 15.7.
Рисунок 15.7 – Схема передачи сериализованных объектов
Модифицированная версия процесса регистрации представлена в листинге 15.13.
267
|
|
|
Листинг 15.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 |
{ |
|
|
|
|
|
|
|
268
|
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 |
{ |
|
|
|
|
if (comboBoxRole.SelectedItem.ToString() |
|
|
|
28 |
Если при заполнении текстовых полей в качестве роли |
|
|
|
== "Студент") |
в comboBoxRole указан «Студент» |
|
29{
Student student = new Student() { Name =
textBoxFIO.Text, NumberGroup = |
Создается объект student и инициализируются все |
30 int.Parse(textBoxNumGroup.Text), |
его свойства согласно значениям, введенным в |
PersonalData = |
соответствующие текстовые поля. |
richTextBoxPersonalData.Text, Photo = |
|
269
this.imageBytes, Specialty = "Программист" };
User user = new User() { Student = student, Login = textBoxLogin.Text,
31Password = textBoxPassword.Text, Role = (string)comboBoxRole.SelectedItem };
this.InitComponentMessage(student, user,
320);
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 =
37professor, Login = textBoxLogin.Text, Password = textBoxPassword.Text, Role = (string)comboBoxRole.SelectedItem };
38this.InitComponentMessage(professor,0); user,
39}
Создается объект user и инициализируются все его свойства согласно значениям, введенным в
соответствующие текстовые поля.
Вызов метода InitComponentMessage и передача в него в качестве параметра first – объекта student, second – объекта user, status – цифры 0.
Если при заполнении текстовых полей в качестве роли в comboBoxRole указан «Преподаватель»
Создается объект professor и инициализируются все его свойства согласно значениям, введенным в
соответствующие текстовые поля.
Создается объект user и инициализируются все его свойства согласно значениям, введенным в
соответствующие текстовые поля.
Вызов метода InitComponentMessage и передача в него в качестве параметра first – объекта student, second – объекта user, status – цифры 0.
270