отчет архитектура2
.docxФГБОУ ВО
Уфимский Государственный Авиационный Технический Университет
Кафедра ВМиК
Отчет по лабораторной работе №2
«Разработка клиент-серверного приложения»
по дисциплине
«Архитектура вычислительных систем и компьютерные сети»
Выполнили:
студенты группы МО-217
Ибрагимова Карина Базретдиновна
Шакиров Айдар Рушанович
Проверил:
Канд. техн. наук, доцент
Валеев Руслан Сагитович
Уфа 2019
Цель работы
Получение навыков разработки клиент-серверных приложений.
Ход выполнения работы:
Создание серверного приложения. Оно должно принимать данные от клиентских приложений, а также передавать их.
- Класс, инкапсулирующий работу с клиентскими TCP подключениями:
public class ClientObject
{
public string Id { get; private set; }
public NetworkStream Stream {get; private set;}
string userName;
TcpClient client;
ServerObject server; // объект сервера
public RichTextBox ChatBox;
public ClientObject(TcpClient tcpClient, ServerObject serverObject, RichTextBox chatBox)
{
Id = Guid.NewGuid().ToString();
client = tcpClient;
server = serverObject;
serverObject.AddConnection(this);
ChatBox = chatBox;
users = new UsersDataSet.UsersDataTable();
UsersTableAdapter usersTable = new UsersTableAdapter();
usersTable.Fill(users);
}
public void Process()
{
try
{
Stream = client.GetStream();
// получаем имя пользователя
string message = GetMessage();
message = userName + " вошел в чат\n";
// посылаем сообщение о входе в чат всем подключенным пользователям
server.BroadcastMessage(message, this.Id);
WriteInChat(message);
// в бесконечном цикле получаем сообщения от клиента
while (true)
{
try
{
message = GetMessage();
message = String.Format("{0}: {1}\n", userName, message);
WriteInChat(message);
server.BroadcastMessage(message, this.Id);
}
catch
{
message = String.Format("{0}: покинул чат\n", userName);
WriteInChat(message);
server.BroadcastMessage(message, this.Id);
break;
}
}
}
catch(Exception)
{
}
finally
{
// в случае выхода из цикла закрываем ресурсы
server.RemoveConnection(this.Id);
Close();
}
}
// чтение входящего сообщения и преобразование в строку
private string GetMessage()
{
byte[] data = new byte[64]; // буфер для получаемых данных
StringBuilder builder = new StringBuilder();
int bytes = 0;
do
{
bytes = Stream.Read(data, 0, data.Length);
builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
}
while (Stream.DataAvailable);
return builder.ToString();
}
// закрытие подключения
public void Close()
{
if (Stream != null)
Stream.Close();
if (client != null)
client.Close();
}
public void WriteInChat(string message)
{
ChatBox.BeginInvoke((MethodInvoker)delegate
{
ChatBox.AppendText(message);
});
}
}
-Класс, инкапсулирующий работу с объектом для прослушивания TCP подключений:
public class ServerObject
{
TcpListener tcpListener; // сервер для прослушивания
List<ClientObject> clients = new List<ClientObject>(); // все подключения
RichTextBox ChatBox;
public ServerObject(RichTextBox chatBox)
{
ChatBox = chatBox;
}
public void AddConnection(ClientObject clientObject)
{
clients.Add(clientObject);
}
public void RemoveConnection(string id)
{
// получаем по id закрытое подключение
ClientObject client = clients.FirstOrDefault(c => c.Id == id);
// и удаляем его из списка подключений
if (client != null)
clients.Remove(client);
}
// прослушивание входящих подключений
public void Listen(IPAddress ip, int port)
{
try
{
tcpListener = new TcpListener(ip, port);
tcpListener.Start();
ChatBox.BeginInvoke((MethodInvoker)delegate
{
ChatBox.AppendText("Сервер запущен. \n");
});
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
ClientObject clientObject = new ClientObject(tcpClient, this, ChatBox);
Task.Run(()=>
{
clientObject.Process();
});
}
}
catch (Exception e)
{
MessageBox.Show("Listen() " + e.Message);
Disconnect();
}
}
//отправка всем
public void BroadcastMessage(string message, string id)
{
byte[] data = Encoding.Unicode.GetBytes(message);
for (int i = 0; i < clients.Count; i++)
{
if (clients[i].Id != id) // если id клиента не равно id отправляющего
{
clients[i].Stream.Write(data, 0, data.Length); //передача данных
}
}
}
public void Disconnect()
{
tcpListener.Stop(); //остановка сервера
for (int i = 0; i < clients.Count; i++)
{
clients[i].Close(); //отключение клиента
}
Environment.Exit(0);
}
}
-Работа основной части приложения
private void StartBtn_Click(object sender, EventArgs e)
{
int port = Convert.ToInt32(PortText.Text);
try
{
server = new ServerObject(ChatBox);
Task.Run(()=> //новый поток
{
server.Listen(IPAddress.Parse(IPText.Text), port);
});
}
catch (Exception ex)
{
server.Disconnect();
MessageBox.Show(ex.Message);
}
}
private void SendBtn_Click(object sender, EventArgs e)
{
string message = "server: " + MessageText.Text + "\n";
ChatBox.AppendText(message);
server.BroadcastMessage(message, "0");
}
Разработка клиентского приложения. Данное приложение передает данные серверному. Также получает данные, отправленные широковещательной рассылкой.
string userName;
string password;
TcpClient client;
NetworkStream stream;
private void ConnectBtn_Click(object sender, EventArgs e)
{
userName = NicknameText.Text;
password = PasswordText.Text;
client = new TcpClient();
try
{
client.Connect(IPText.Text, Convert.ToInt32(PortText.Text)); //подключение клиента
stream = client.GetStream(); // получаем поток
string message = userName + "%" + password;
byte[] data = Encoding.Unicode.GetBytes(message);
stream.Write(data, 0, data.Length);
// запускаем новый поток для получения данных
Task.Run(() =>
{
ReceiveMessage();
});
ChatBox.AppendText($"Добро пожаловать, {userName} \n");
}
catch (Exception ex)
{
MessageBox.Show("ConnectBtn_Click() " + ex.Message);
}
}
void SendMessage(string message)
{
try
{
byte[] data = Encoding.Unicode.GetBytes(message);
stream.Write(data, 0, data.Length);
ChatBox.AppendText("Вы: " + message + "\n");
}
catch (Exception)
{
}
}
void ReceiveMessage()
{
while (true)
{
try
{
byte[] data = new byte[64]; // буфер для получаемых данных
StringBuilder builder = new StringBuilder();
int bytes = 0;
do
{
bytes = stream.Read(data, 0, data.Length);
builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
}
while (stream.DataAvailable);
string message = builder.ToString();
if (string.IsNullOrWhiteSpace(message)) //костыль, чтобы понять, что подключение больше не работает
SendMessage("err");
ChatBox.BeginInvoke((MethodInvoker)delegate
{
ChatBox.AppendText(message);//вывод сообщения
});
Thread.Sleep(105);
}
catch (Exception)
{
ChatBox.BeginInvoke((MethodInvoker)delegate
{
ChatBox.AppendText("Подключение прервано" + "\n");//вывод сообщения
});
Disconnect();
return;
}
}
}
void Disconnect()
{
if (stream != null)
stream.Close();//отключение потока
if (client != null)
client.Close();//отключение клиента
//Environment.Exit(0); //завершение процесса
}
private void SendBtn_Click(object sender, EventArgs e)
{
SendMessage(MessageText.Text);
}
Интерфейс программы:
Серверное приложение:
Клиентское приложение:
Заключение:
В ходе лабораторной работы получены навыки разработки клиент-серверных приложений.