Добавил:
Преподаватель Колледжа информационных технологий Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лекции / РАЗРАБОТКА ПРИЛОЖЕНИЯ С КЛИЕНТ-СЕРВЕРНОЙ АРХИТЕКТУРОЙ

.pdf
Скачиваний:
63
Добавлен:
08.05.2022
Размер:
902.39 Кб
Скачать

5. Класс EntityModelContainer, представляющий контекст данных,

используемый для взаимодействия с базой данных.

 

Листинг 24.7 – Класс контекста данных

 

 

 

1

namespace MyLib

 

2

{

 

3

public partial class EntityModelContainer : DbContext

 

4

{

 

5

public EntityModelContainer() :

 

base("name=EntityModelContainer")

 

 

 

6

{}

 

7

public virtual DbSet<User> UserSet { get; set; }

 

8

public virtual DbSet<Student> StudentSet { get; set;

 

}

 

 

 

9

public virtual DbSet<Professor> ProfessorSet { get;

 

set; }

 

 

 

10

public virtual DbSet<Thesis> ThesisSet { get; set; }

 

11

}

 

12

}

 

 

6. Класс SerializeAndDeserialize, хранящий методы для

сериализации (Serialize) и десериализации (Deserialize) объектов.

 

Листинг 24.8 – Класс сериализации и десериализации

 

 

 

1

namespace MyLib

 

2

{

 

3

public class SerializeAndDeserialize

 

4

{

 

5

public static Message Serialize(object

 

anySerializableObject)

 

 

 

6

{

 

7

IFormatter formatter = new BinaryFormatter();

 

8

formatter.Binder = new CustomBinder();

 

9

using (var memoryStream = new MemoryStream())

 

10

{

 

11

formatter.Serialize(memoryStream,

 

 

anySerializableObject);

 

12

return new Message { Data = memoryStream.ToArray() };

 

13

}

 

14

}

 

15

public static object Deserialize(Message message)

 

16

{

 

 

11

 

17

IFormatter formatter = new BinaryFormatter();

 

18

formatter.Binder = new CustomBinder();

 

 

19

using

(var

memoryStream

=

new

MemoryStream(message.Data))

 

 

20

{

 

 

 

 

21

return formatter.Deserialize(memoryStream);

 

22

}

 

 

 

 

23

}

 

 

 

 

24

}

 

 

 

 

25

}

 

 

 

 

Для корректной сериализации и десериализации в строке 8 и 18 свойству объекта formatter присваивается экземпляр биндера CustomBinder,

созданного классе 4.

7. Класс Message, представляющий в качестве объекта пакет данных,

передаваемый посредством TCP-протокола через компьютерную сеть от клиента к серверу и наоборот, от сервера к клиенту.

Листинг 24.9 – Класс пакетов данных

1

namespace MyLib

2

{

3

[Serializable]

4

public class Message

5

{

6

public byte[] Data { get; set; }

7

}

8

[Serializable]

9

public class ComplexMessage

10

{

11

public Message First { get; set; }

12

public Message Second { get; set; }

13

public int NumberStatus { get; set; }

14

}

15

}

Класс Message представляет собой пакет с данными об одном сериализованном объекте, а класс ComplexMessage – о двух сериализованных объектах (First и Second). Сериализованные данные об объекте хранятся в массиве байтов Data.

12

Свойство NumberStatus позволяет при отправке пакета от одной машины к другой отследить тип запроса, который необходимо выполнить после приема данных. Например, если значение свойства равно 0, то выполняется запрос на регистрации, а если равно 1, то выполняется запрос на авторизацию пользователя и т.д.

3. Серверная часть приложения

Рассмотрим реализацию серверной части приложения.

Для начала создаем отдельный проект (в нашем случае LR8_SERVER).

В новый проект добавляем ссылку на раннее созданную библиотеку классов

MyLib.

Сервер будет принимать от клиента пакеты данных, которые будут содержать сериализованные объекты и тип запроса. После приема данных необходимо организовать взаимодействие с базой данных – или для добавления, или для извлечения данных. Для этого необходимо создать базу данной с аналогичной структурой, как она была реализована в десктопной версии приложения (в лабораторной работе 7).

Добавляем в проект следующие классы:

1. Класс ServerObject – класс, описывающий свойства и метода,

требуемые для обеспечения работоспособности TCP-сервера, который будет осуществлять прием и отправку данных посредством TCP-протокола через компьютерную сеть.

Реализация класса сервера представлена в листинге 24.10.

 

 

 

 

Листинг 24.10 – Класс сервера

 

 

 

1

public class ServerObject

 

2

{

 

 

 

3

static public TcpListener

tcpListener; // сервер для

прослушивания

 

 

 

 

 

4

List<ClientObject> clients = new List<ClientObject>();

5

ClientObject clientObject = null;

6

protected

internal

void

AddConnection(ClientObject

clientObject)

 

 

 

 

 

7

{

 

 

 

 

 

 

13

 

8

clients.Add(clientObject);

 

 

 

9

}

 

 

 

 

10

protected internal void Listen()

 

 

11

{

 

 

 

 

12

tcpListener = new TcpListener(IPAddress.Any, 8888);

13

tcpListener.Start();

 

 

 

14

while (true)

 

 

 

 

15

{

 

 

 

 

16

TcpClient tcpClient = tcpListener.AcceptTcpClient();

17

clientObject = new ClientObject(tcpClient, this);

18

Thread

clientThread

=

new

Thread(new

 

ThreadStart(clientObject.Process));

 

 

19

clientThread.Start();

 

 

 

20

}

 

 

 

 

21

}

 

 

 

 

22

}

 

 

 

 

Все подключенные клиенты будут храниться в коллекции clients. С

помощью метода AddConnection мы можем добавлять объекты в эту коллекцию.

Основной метод - Listen(), в котором будет осуществляться прослушивание всех входящих подключений. При получении подключения будет запускаться новый поток, в котором будет выполняться метод Process

объекта ClientObject.

2. Класс ClientObject - класс, описывающий свойства и метода,

требуемые для обеспечения работоспособности TCP-клиента, который будет осуществлять отправку данных посредством TCP-протокола через компьютерную сеть и прием данных, отправленных сервером.

Реализация класса клиента представлена в листинге 24.11.

14

Листинг 24.11 – Класс клиента

 

1

public class ClientObject

 

 

2

{

 

 

3

protected internal string Id { get; private set; }

Идентификатор подключаемого к серверу

 

клиента

 

 

 

 

4

protected internal NetworkStream Stream { get;

Поток, используемый для взаимодействия с

 

private set; }

клиентом

 

 

 

5

TcpClient client;

Объект TCP-клиента

 

6

ServerObject server;

Объект сервера

 

7

MyLib.Message m, m1, m2;

Экземпляры класса Message из библиотеки

 

8

MyLib.ComplexMessage cm = new ComplexMessage();

MyLib, созданной на предыдущем этапе

 

9

public ClientObject(TcpClient tcpClient,

Конструктор класса клиента

 

ServerObject serverObject)

 

 

 

 

 

10

{

 

 

 

 

Инициализация свойства Id (метод NewGuid

 

11

Id = Guid.NewGuid().ToString();

генерирует случайный уникальный

 

 

 

идентификатор)

 

12

client = tcpClient;

Инициализация свойства tcpClient

 

13

server = serverObject;

Инициализация свойства serverObject

 

14

serverObject.AddConnection(this);

Добавление в коллекцию подключений класса

 

ServerObject нового подключения

 

 

 

 

15

Stream = client.GetStream();

Связывание потока Stream с TCP-клиентом

 

client

 

 

 

 

16

}

 

 

17

public void Process()

Метод, реализующий протокол обмена

 

сообщениями с клиентом

 

 

 

 

18

{

 

 

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

{

…то выполняется запрос на добавление нового

 

 

пользователя в базу данных

 

 

 

 

 

 

 

16

 

 

 

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

 

 

17

 

 

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.

 

 

 

 

 

18

 

 

 

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

 

 

 

 

 

 

78

}

 

 

 

 

19

 

 

 

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 (статус неудачной

 

 

 

 

авторизации)

 

20