- •Задание на курсовую работу.
- •Введение
- •1.Основная часть
- •1.1Постановка задачи
- •1.2.Теоритические основы разработки «клиент-серверных» приложений
- •Заключение.
- •Список литературы
- •Приложение №1
- •1.3.Разработка и описание алгоритма работы приложения
- •1.4.Описание cтруктуры программы.
- •1.5.Руководство пользователя.
- •1.6.Результаты применения программы
1.3.Разработка и описание алгоритма работы приложения
Программа предназначена для вывод на экран информации от двух серверов.
Входной информацией являются данные, которые оператор с помощью визуальных компонентов вводит в соответствующую строку
Входная информация:
1;
2;
Е.
Выходной информацией является вывод параметров на экран консоли
Выходная информация:
код последней ошибки;
текущее положение каретки
полное имя модуля текущего процесса;
идентификаторы серверных и клиентских процессов
Рис.1. UML-диаграмма деятельности приложения
1.4.Описание cтруктуры программы.
Для межпроцессного взаимодействия был выбран метод именнованые каналы.Именованные каналы обеспечивают межпроцессное взаимодействие между сервером канала и одним или несколькими клиентами канала. Они предоставляют больше функциональных возможностей, чем анонимные каналы, которые обеспечивают межпроцессное взаимодействие на локальном компьютере. Именованные каналы поддерживают полную дуплексную связь по сети и несколько экземпляров сервера, связь на основе сообщений и олицетворение клиента, позволяющее подключающимся процессам использовать собственные наборы разрешений на удаленных серверах.
Для реализации именованных каналов используются классы NamedPipeServerStream и NamedPipeClientStream.
Для создания потоков был исползован класс Thread
Для вывода информации в консоль использовался метод Console.WriteLine.
Для чтения и записи в канал были использованы классы StreamReader StreamWriter
1.5.Руководство пользователя.
Оператор запускает приложение client.exe. В открывшейся консоли для соединения с 1-ым сервером надо ввести цифру «1» и нажать «Enter», на экран будет выведена информация о коде последней ошибки, текущем положении каретки. Для продолжения нажать кнопку «Enter». Далее для соединения со 2-ым сервером надо ввести цифру «2» и нажать «Enter», на экран будет выведена информация о полном имени модуля текущего процесса, идентификаторы серверных и клиентских процессов. Для выхода ввести букву «E» из латинской раскладки и нажать «Enter».
1.6.Результаты применения программы
Рис.2.Консоль
Заключение.
Формализованы и уточнены данные, в результате которых был разработан алгоритм решения задачи.
Разработан логика программы, учитывающая взаимодействие с обычным пользователем.
Создан проект с программным кодом на языке C# с использованием метода, именованный каналы.
Протестирована работа программы.
Список литературы
Э.Таненбаум, Х.Бос. Современные операционные системы. 4-изд. – СПб.: Питер, 2015
В.Г.Олифер, Н.А.Олифер. Сетевые операционные системы. – СПб.: Питер, 2009
Марк Руссинович, Дэвид Соломон, Алекс Ионеску, Павел Йосифович. Внутреннее устройство Windows.7-е издание . - СПб.: Питер, 2018
http://msdn.microsoft.com
http://ru.wikipedia.org/wiki/Клиент-сервер
http://www.intuit.ru/department/internet/mwebtech/5/
Приложение №1
Код клиента
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;
using System.Text;
using System.Threading;
public class PipeClient
{
private static string strNamePipe = "testpipe";
public static void Main(string[] args)
{
/*
* Работает бесконечный цикл. Для выхода необходимо ввести символ "E". Для соединения с серверными процессами необходимо ввести номер сервера 1 или 2
*/
do
{
string q;
Console.WriteLine("Enter number of server (1, 2) to connect server or character E for exit: \n");
q = Console.ReadLine();
if (q.ToUpper().CompareTo("E") == 0)
{
return;
}
else if (q.CompareTo("1") == 0 || q.CompareTo("2") == 0)
{
// Создаем клиентское подключение к именнованому каналу. Наименвоание канала равно strNamePipe + введенный номер в переменной q
var pipeClient =
new NamedPipeClientStream(".", strNamePipe + q,
PipeDirection.InOut, PipeOptions.None,
TokenImpersonationLevel.Impersonation);
Console.WriteLine("Connecting to server...\n");
pipeClient.Connect();
// Создаем экземпляр класса для чтение из канала
StreamReader sr = new StreamReader(pipeClient);
// StreamWriter sw = new StreamWriter(pipeClient);
string temp;
Console.WriteLine("Client connected to server\n");
Console.WriteLine("There are currently {0} pipe server instances open.",
pipeClient.NumberOfServerInstances);
// Читаем все строки символов пока не будет достигнут конец потока
while ((temp = sr.ReadLine()) != null)
{
// Выводим полученную информацию
Console.WriteLine("Received from server: {0}", temp);
}
// Перед окончанием процесса чтение из потока ждем нажатия любой клавиши
Console.Write("Press Enter to continue...");
Console.ReadLine();
//
pipeClient.Dispose();
}
} while (true);
}
}
Код 1 сервер
using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
public class PipeServer
{
// Число серверных потоков
private static int numThreads = 3;
public static void Main()
{
int i;
// ServerThread();
Console.WriteLine("Waiting for client connect...\n");
// Запуск северных потоков
Thread[] servers = new Thread[numThreads];
for (i = 0; i < numThreads; i++)
{
servers[i] = new Thread(ServerThread);
servers[i].Start();
}
Thread.Sleep(250);
// Цикл проверки завершения серверных потоков
while (i > 0)
{
for (int j = 0; j < numThreads; j++)
{
if (servers[j] != null)
{
// Проеряем завершение потока в течении 250 мс, если условие истинно, то поток завершился.
if (servers[j].Join(250))
{
Console.WriteLine("Server thread[{0}] finished.", servers[j].ManagedThreadId);
servers[j] = null;
i--; // decrement the thread watch count
}
}
}
}
Console.WriteLine("\nServer threads exhausted, exiting.");
}
/*
Метод запускает серверный поток
*/
private static void ServerThread()
{
try
{
// Создаем именованный канал
NamedPipeServerStream pipeServer =
new NamedPipeServerStream("testpipe1", PipeDirection.InOut, numThreads);
int threadId = Thread.CurrentThread.ManagedThreadId;
// Создаем экземпляры для чтения из канала и записи в канал
StreamReader sr = new StreamReader(pipeServer);
StreamWriter sw = new StreamWriter(pipeServer);
do
{
try
{
// Ожидает подключения клиента
pipeServer.WaitForConnection();
// Выводим в консоль Имя клиента и номер потока сервера, к которому подключился клиент
Console.WriteLine("Client {0} connected on thread[{1}].", pipeServer.GetImpersonationUserName(), threadId);
sw.Flush();
// Выводим последнюю ошибку
int error = Marshal.GetLastWin32Error();
Console.WriteLine("Last win32 error was: " + error);
sw.WriteLine("Last win32 error was: " + error);
// Выводим позицию курсора
Console.WriteLine("Cursor position: left {0}, top {1}", Console.CursorLeft, Console.CursorTop);
sw.WriteLine("Cursor position: left {0}, top {1}", Console.CursorLeft, Console.CursorTop);
// Записывает все данные из буфера в основной поток
sw.Flush();
}
// Обработка ошибок ввода-вывода
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
finally
{
if (pipeServer.IsConnected)
{
// Ожидает завершения считывания всех отправленных байтов на противоположном конце канала
pipeServer.WaitForPipeDrain();
}
// Отсоединяет текущее подключение
pipeServer.Disconnect();
}
} while (true);
}
// Обработка ошибок, если произошел сбой в работе серверного потока
catch (Exception e)
{
Console.WriteLine("ERROR: {0}", e.Message);
Console.ReadLine();
}
}
}
Код второй сервер
using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
public class PipeServer
{
// Число серверных потоков
private static int numThreads = 3;
public static void Main()
{
int i;
// ServerThread();
Console.WriteLine("Waiting for client connect...\n");
// Запуск северных потоков
Thread[] servers = new Thread[numThreads];
for (i = 0; i < numThreads; i++)
{
servers[i] = new Thread(ServerThread);
servers[i].Start();
}
Thread.Sleep(250);
// Цикл проверки завершения серверных потоков
while (i > 0)
{
for (int j = 0; j < numThreads; j++)
{
if (servers[j] != null)
{
// Проеряем завершение потока в течении 250 мс, если условие истинно, то поток завершился.
if (servers[j].Join(250))
{
Console.WriteLine("Server thread[{0}] finished.", servers[j].ManagedThreadId);
servers[j] = null;
i--; // decrement the thread watch count
}
}
}
}
Console.WriteLine("\nServer threads exhausted, exiting.");
}
/*
Метод запускает серверный поток
*/
private static void ServerThread()
{
try
{
// Создаем именованный канал
NamedPipeServerStream pipeServer =
new NamedPipeServerStream("testpipe2", PipeDirection.InOut, numThreads);
int threadId = Thread.CurrentThread.ManagedThreadId;
// Создаем экземпляры для чтения из канала и записи в канал
StreamReader sr = new StreamReader(pipeServer);
StreamWriter sw = new StreamWriter(pipeServer);
do
{
try
{
// Ожидает подключения клиента
pipeServer.WaitForConnection();
// Выводим в консоль Имя клиента и номер потока сервера, к которому подключился клиент
Console.WriteLine("Client {0} connected on thread[{1}].", pipeServer.GetImpersonationUserName(), threadId);
sw.Flush();
// Выводим наименование модуля текущего процесса (сервера)
string curProc = Process.GetCurrentProcess().MainModule.ModuleName;
sw.WriteLine("CurrentProcess Modulename: {0}", curProc);
/*
* Выводим ид серверных и клиентских процессов
* Получаем список всех процессов и по имени процесса определяем интересующие нас процессы
*/
Process[] proc = Process.GetProcesses();
for (int i = 0; i < proc.Length; i++)
{
if (proc[i].ProcessName.CompareTo("srv1") == 0 || proc[i].ProcessName.CompareTo("srv2") == 0 || proc[i].ProcessName.CompareTo("client") == 0 )
{
sw.WriteLine("{0}: id = {1}", proc[i].ProcessName, proc[i].Id);
}
}
// Записывает все данные из буфера в основной поток
sw.Flush();
}
// Обработка ошибок ввода-вывода
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
finally
{
if (pipeServer.IsConnected)
{
// Ожидает завершения считывания всех отправленных байтов на противоположном конце канала
pipeServer.WaitForPipeDrain();
}
// Отсоединяет текущее подключение
pipeServer.Disconnect();
}
} while (true);
}
// Обработка ошибок, если произошел сбой в работе серверного потока
catch (Exception e)
{
Console.WriteLine("ERROR: {0}", e.Message);
Console.ReadLine();
}
}
}
