Задание на курсовую работу
Разработать многозадачное приложение, выполняющее получение, сбор и вывод системной информации в соответствии с вариантом задания:
№ вар. |
Способ коммуникации |
Процесс 1 определяет и передает |
Процесс 2 определяет и передает |
3 |
сокеты |
- текущее местное время - продолжительность текущего сеанса работы |
- приоритеты клиентского и серверных процессов; - дельта-приоритеты их потоков |
Разработка и описание алгоритма
Сервер ожидает входящее соединение на порту 15000 или 1500. После получения соединения он производит вычисления и получает определенные данные и отправляет их клиенту. При запросе соединения мы начинаем передавать данные на тот порт, который передает клиент при коннекте, это позволяет нам передавать данные конкретному клиенту, а не всем сразу.
Клиент соединяется с сервером на порту 15000 или 15001, после успешного подключения он получает все необходимые данные из сервера и разрывает соединение.
Описание cтруктуры программы
В серверной части приложений есть класс SocketServer для работы с сокетами, где происходит основная часть полезной работы, то есть получение требуемых заданием данных и формируется сообщение и соответственно оно отправляется клиенту. В классе основной функцией является Listening, в ней происходят расчеты данных и формирование сообщения, а отправка идет с помощью функций SendAll и Send. В последней функции происходит побайтовая отправка сообщения, в котором хранятся необходимые данные. В конце сообщения всегда должно присутствовать слово end, сигнализирующей об окончании сообщения, чтобы клиент перестал принимать данные и закрыл соединение.
В клиентской части существует класс SocketClient, где происходит подключение к сокету сервера, а также получение сообщений.
Руководство пользователя.
Сервер обладает кнопкой выход. При нажатии этой кнопки закрывается соединение и освобождаются все ресурсы процесса. Соединение, обработка и посыл данных выполняется в «тихом» режиме без контроля пользователем.
Клиент имеет 4 кнопки. Во – первых, это «Получить данные с первого сервера» – при нажатии на кнопку происхдоитесли сервер доступен, тогда мы устанавливаем с ним соединение и получаем данные. В случае если подключение не установлено, получаем сообщение об этом. Во – вторых, это «Получить данные со второго сервера» аналогично предыдущей кнопке. В-третьих, «Очистить» – очищает список сообщений в левой части экрана. В – четвертых, «Выход» – кнопка осуществляет выход из программы.
Результаты работы программ.
Результат проведенной работы представлен на рисунке 1.
Рисунок 1- результат клиент-серверного взаимодействия
Приложение
Код для первого сервера:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace Server1
{
public partial class Form1: Form
{
SocketServer server;
public Form1()
{
InitializeComponent();
// получение локального IP адреса компьютера
string MyIp = "";
foreach (IPAddress ip in Dns.GetHostByName(Dns.GetHostName()).AddressList) {
MyIp = ip.ToString();
break;
}
server = new SocketServer(MyIp, 15000);
server.Start();
Thread list = new Thread(List);
list.IsBackground = true;
list.Start();
}
// кнопка выхода
private void btnExit(object sender, EventArgs e) {
server.Dispose();
this.Dispose();
Application.Exit();
}
// добавление сведений о доставке сообщения, а то есть указывается адресат
private void List() {
for (; ; Thread.Sleep(200))
if (server.ClientList.Count != lbx_clientList.Items.Count) {
lbx_clientList.Invoke(new MethodInvoker(delegate {
lbx_clientList.Items.Clear();
}));
for (int i = 0; i < server.ClientList.Count; i++)
lbx_clientList.Invoke(new MethodInvoker(delegate {
lbx_clientList.Items.Add("Доставлено по адресу: " + server.ClientList[i]);
}));
}
}
}
class SocketServer
{
public Socket server;
private IPEndPoint ip;
private List<Thread> thread_list; // список потоков
private int max_conn;
public List<string> ClientList = new List<string>();
// создание и инициализация сокета
public SocketServer(string ip, Int32 port)
{
this.max_conn = 2;
this.thread_list = new List<Thread>();
this.ip = new IPEndPoint(IPAddress.Parse(ip), port);
this.server = new Socket(this.ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.server.Bind(this.ip); // cвязываение сокет с конечной локальной точкой
this.server.Listen(this.max_conn); // макс кол-во слушателей
}
// запуск потока
public void Start() {
for (int i = 0; i < this.max_conn; i++) {
Thread th = new Thread(Listening);
th.Start();
thread_list.Add(th);
}
}
// закрытие сокета
public void Dispose() {
foreach (Thread th in thread_list) {
th.Interrupt();
}
server.Close();
}
// прослушивание
// здесь идет расчет текущего местного времени и времени работы компьютера, а также запись в файл и отправка их.
private void Listening() {
while (true) {
try {
using (Socket client = this.server.Accept()) {
this.ClientList.Add(client.RemoteEndPoint.ToString());
client.Blocking = true;
if (client.Connected) {
List<string> message = new List<string>();
message.Add("Текущее местное время: " + System.DateTime.Now.ToLongTimeString());
String strResult = String.Empty;
strResult += Convert.ToString(Environment.TickCount / 86400000) + " дней, ";
strResult += Convert.ToString(Environment.TickCount / 3600000 % 24) + " часов, ";
strResult += Convert.ToString(Environment.TickCount / 120000 % 60) + " минут, ";
strResult += Convert.ToString(Environment.TickCount / 1000 % 60) + " секунд.";
message.Add("Время работы компьютера: " + strResult);
message.Add("[end]");
SendAll(client, message);
}
}
} catch (SocketException ex) {
}
}
}
// отправление всего сообщения
public void SendAll(Socket handler, List<string> message) {
for (int i = 0; i < message.Count;) {
Send(message[i], handler);
message.RemoveAt(i);
Thread.Sleep(5);
}
}
// отправка указанного кол-ва байтов по сокету
public void Send(string message, Socket handler) {
byte[] tosend = Encoding.UTF8.GetBytes(message);
try {
handler.Send(tosend, 0, tosend.Length, SocketFlags.None);
} catch {
}
}
}
}
Код для второго сервера:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Diagnostics;
namespace server2
{
public partial class Form1 : Form
{
SocketServer server;
public Form1()
{
InitializeComponent();
string MyIp = "";
foreach (IPAddress ip in Dns.GetHostByName(Dns.GetHostName()).AddressList)
{
MyIp = ip.ToString();
break;
}
server = new SocketServer(MyIp, 15001);
server.Start();
Thread list = new Thread(List);
list.IsBackground = true;
list.Start();
}
// кнопка выхода
private void btnExit(object sender, EventArgs e)
{
server.Dispose();
this.Dispose();
Application.Exit();
}
// добавление сведений о доставке сообщения, а то есть указывается адресат
private void List() {
for (; ; Thread.Sleep(200))
if (server.ClientList.Count != lbx_clientList.Items.Count)
{
lbx_clientList.Invoke(new MethodInvoker(delegate {
lbx_clientList.Items.Clear();
}));
for (int i = 0; i < server.ClientList.Count; i++)
lbx_clientList.Invoke(new MethodInvoker(delegate {
lbx_clientList.Items.Add("Доставлено по адресу: " + server.ClientList[i]);
}));
}
}
}
class SocketServer
{
public Socket server;
private IPEndPoint ip;
private List<Thread> thread_list;
private int max_conn;
public List<string> ClientList = new List<string>();
public SocketServer(string ip, Int32 port)
{
this.max_conn = 2;
this.thread_list = new List<Thread>();
this.ip = new IPEndPoint(IPAddress.Parse(ip), port);
this.server = new Socket(this.ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.server.Bind(this.ip); this.server.Listen(this.max_conn);
}
// запуск потока
public void Start()
{
for (int i = 0; i < this.max_conn; i++)
{
Thread th = new Thread(Listening);
th.Start();
thread_list.Add(th);
}
}
// освобождение сокета
public void Dispose()
{
foreach (Thread th in thread_list)
{
th.Interrupt();
}
server.Close();
}
// обработка приоритетов
private string Priority(int number)
{
switch (number)
{
case 4: { return ("4 - Приоритет маленький"); }
case 6: { return ("6 - Приоритет ниже нормального"); }
case 8: { return ("8 - Приоритет нормальный"); }
case 10: { return ("10 - Приоритет выше нормального"); }
case 13: { return ("13 - Приоритет высокий"); }
case 24: { return ("24 - Приоритет реального времени"); }
default: { return ("Приоритет неизвестен"); }
}
}
// подключение к сокету и отправка данных и приоритетах потоков и процессов.
private void Listening()
{
while (true)
{
try
{
using (Socket client = this.server.Accept())
{
this.ClientList.Add(client.RemoteEndPoint.ToString());
client.Blocking = true;
if (client.Connected)
{
// получение данных о приоритетах потоков процесса сервера
List<string> message = new List<string>();
Process[] serverProc = Process.GetProcessesByName("server2");
for (int i = 0; i < serverProc.Length; i++)
{
ProcessThreadCollection ListServer = serverProc[i].Threads;
message.Add("Сервер " + ": " + Priority(serverProc[i].BasePriority));
message.Add("Количество потоков в сервере - " + ListServer.Count + ".");
for (int j = 0; j < ListServer.Count; j++)
message.Add((j+1) + ". Поток №" + ListServer[j].Id + ": " + Priority(ListServer[j].BasePriority));
}
// получение данных о приоритетах потоков процесса клиента
Process[] clientProc = Process.GetProcessesByName("kursovay");
for (int i = 0; i < clientProc.Length; i++)
{
ProcessThreadCollection ListServer = clientProc[i].Threads;
message.Add("Клиент " + ": " + Priority(clientProc[i].BasePriority));
message.Add("Количество потоков в клиенте - " + ListServer.Count + ".");
for (int j = 0; j < ListServer.Count; j++)
message.Add((j+1) + ". Поток №" + ListServer[j].Id + ": " + Priority(ListServer[j].BasePriority));
}
message.Add("[end]");
SendAll(client, message);
}
}
}
catch (SocketException ex)
{
}
}
}
// отправка всех сообщений
public void SendAll(Socket handler, List<string> message)
{
for (int i = 0; i < message.Count;)
{
Send(message[i], handler);
message.RemoveAt(i);
Thread.Sleep(5);
}
}
// побайтовая отправка сообщения
public void Send(string message, Socket handler)
{
byte[] tosend = Encoding.UTF8.GetBytes(message);
try
{
handler.Send(tosend, 0, tosend.Length, SocketFlags.None);
}
catch
{
}
}
}
}
Код клиента:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace kursovay
{
public partial class Form1 : Form
{
int port;
static SocketClient client;
public Form1()
{
InitializeComponent();
string MyIp = "";
foreach (IPAddress ip in Dns.GetHostByName(Dns.GetHostName()).AddressList)
{
MyIp = ip.ToString();
break;
}
label1.Text = "Текущий ip: " + MyIp.ToString();
}
// получение локального Ip адреса и создание сокета
private void connection()
{
string MyIp = "";
foreach (IPAddress ip in Dns.GetHostByName(Dns.GetHostName()).AddressList)
{
MyIp = ip.ToString();
break;
}
client = new SocketClient(MyIp, this.port);
if (client.Connect())
{
lbx_message.Invoke(new MethodInvoker(delegate {
lbx_message.Items.Add("Соединение с сервером установлено!");
lbx_message.Items.Add("Ожидайте...");
}));
lbx_message.Invoke(new MethodInvoker(delegate {
lbx_message.Items.Add("Полученные даннные:");
}));
Status();
} else
{
lbx_message.Invoke(new MethodInvoker(delegate {
lbx_message.Items.Add("Невозможно установить соединение с сервером!");
lbx_message.Items.Add("Попробуйте позже!");
}));
}
}
// обращение к серверу №1
private void btnServer1(object sender, EventArgs e) {
port = 15000;
Thread connect = new Thread(connection);
connect.Start();
connect.IsBackground = true;
}
// получение данных с сокета
private void Status()
{
for (; ; )
{
client.Receive();
try
{
// если получение слово указывающее на конец строки завершаем цикл приема сообщения
if (client.ReceiveMessage[client.ReceiveMessage.Count - 1] == "[end]")
break;
}
catch
{
}
}
for (int i = 0; i < client.ReceiveMessage.Count;)
{
if (client.ReceiveMessage[i] != "[end]")
lbx_message.Invoke(new MethodInvoker(delegate {
lbx_message.Items.Add(client.ReceiveMessage[i]);
}));
client.ReceiveMessage.RemoveAt(i);
}
}
// обращение к серверу №2
private void bthServer2(object sender, EventArgs e)
{
this.port = 15001;
Thread connect = new Thread(connection);
connect.Start();
connect.IsBackground = true;
}
// очищение списка полученных данных
private void btnClear_Click(object sender, EventArgs e)
{
lbx_message.Items.Clear();
}
//закрытие приложения
private void btnExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
class SocketClient
{
public Socket client;
private IPEndPoint ip;
public List<string> SendMessage = new List<string>();
public List<string> ReceiveMessage = new List<string>();
public SocketClient(string ip, Int32 port)
{
this.ip = new IPEndPoint(IPAddress.Parse(ip), port);
this.client = new Socket(this.ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public bool Connect()
{
try
{
this.client.Connect(this.ip);
return true;
}
catch
{
return false;
}
}
// получение данных из сокета
public void Receive()
{
string message = String.Empty;
byte[] GetBytes = new byte[1024];
try
{
int b = client.Receive(GetBytes);
message = Encoding.UTF8.GetString(GetBytes, 0, b);
if (message != "")
this.ReceiveMessage.Add(message);
}
catch
{
}
}
// осуществляет отключение
public void Disconnect()
{
this.client.Disconnect(false);
}
}
}