Управление удаленной рабочей станцией

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 12:19, 22 декабря 2015.

Данная статья посвящена программному продукту, который обеспечивает управление удаленной рабочей станцией в локальной сети. Рассматриваемое программное обеспечение реализовано на языке программирования C#.

Актуальность работы

В настоящее время использование программ, обеспечивающих подключение к удаленным рабочим станциям, является актуальным. Такие программы удобно использовать для удаленной работы, например, из дома для подключения в офис и наоборот — для доступа к своему домашнему ПК, для системного администрирования целого парка компьютеров и серверов. Они также нашли широкое применение во многих компаниях, занимающихся разработкой какого – либо программного обеспечения. С помощью ПО для удаленного подключения компании обеспечивают своих заказчиков помощью по работе и настройке предоставляемого ими программного продукта.

Структура программного продукта

Разработанный программный продукт состоит из двух частей: серверное приложение и клиентское приложение.

Серверное приложение

Задачи серверного приложения

Приложение - сервер решает следующие задачи:

  • Ведение журнала событий.
  • Регистрация нового клиента в системе.
  • Аутентификация и авторизация пользователей.
  • Обмен данными с клиентами.
  • Операция, обратная авторизации пользователя.

Предоставляемый функционал

Весь необходимый набор методов содержится в классе RDServer. Ниже в таблице представлены некоторые из них:

Имя метода Уровень доступа Параметры Возвращаемое значение Описание
Start Публичный - - Запуск сервера
BroadCastConnections Частный - - Прием широковещательного запроса от клиентских приложений
GetTCPConnections Частный - - Прием TCP запросов от клиентов
TcpClientConnection Частный Конечная точка взаимодействия (сокет) - Обработка TCP запроса от одного клиента
ClientLogIn Частный Конечная точка взаимодействия (сокет), Сообщение клиента - Авторизация клиента
ClientLogOut Частный Конечная точка взаимодействия (сокет), Сообщение клиента - Выход клиента из системы

Примеры реализации

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

private void GetTCPConnections()
{
    try
    {
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, serverEndpoit.portNumber);
        serverTCP.Init(SocketType.Stream, ProtocolType.Tcp, endPoint);
        fileLogger.WriteLogFile("Сервер ожидает TCP запросы от клиентов\n");
        while (true)
        {
            Socket client = null;
            serverTCP.AcceptClient(out client);
            fileLogger.WriteLogFile("TCP клиент: " + ((IPEndPoint)client.RemoteEndPoint).Address.ToString() + ":" +
                   Convert.ToString(((IPEndPoint)client.RemoteEndPoint).Port) + '\n');
            Console.WriteLine("Client : {0}:{1}", ((IPEndPoint)client.RemoteEndPoint).Address, ((IPEndPoint)client.RemoteEndPoint).Port);
            ParameterizedThreadStart th = new ParameterizedThreadStart(TcpClientConnection);

            Thread clientThread = new Thread(th);
            clientThread.Start(client);
        }
    }
    catch (Exception exception)
    {
        Console.WriteLine(exception.Message);
    }
}

Клиентское приложение

Задачи клиентского приложения

Приложение - клиент решает следующие задачи:

  • Ведение журнала событий.
  • Авторизация пользователя.
  • Автоматическое обнаружение сервера.
  • Обмен данными с сервером.
  • Удаленное управление мышью.
  • Удаленной управление клавиатурой.
  • Демонстрация рабочего стола.
  • Выход из системы.

Предоставляемый функционал

Функционал клиентского приложения содержится в классе RDClient. Описание некоторых методов класса представлено ниже:

Имя метода Уровень доступа Параметры Возвращаемое значение Описание
FindServer Публичный - - Автоматическое обнаружение сервера
Start Публичный - - Запуск клиентского приложения
ConnectToOtherClient Публичный Индекс клиента в списке клиентов - Установление подключение с другим участником сетевого взаимодействия
LogIn Публичный Логин, пароль - Авторизация
LogOut Публичный - - Выход из системы
SendMouseCommand Публичный Координаты позиции курсора мыши, тип команды (смещение курсора, нажатие клавиш) - Удаленное управление мышью
SendKeyBoardCommand Публичный Клавиша клавиатуры - Удаленное управление клавиатурой
ReloadOnlineClientsList Публичный - - Обновление списка клиентов, находящихся в сети
CloseConnectionToClients Публичный - - Завершает все установленные соединения.
ScreenWasReceived Частный Конечная точка взаимодействия (сокет) - Обработчик получения кадра рабочего стола.
MouseCommandReceived Частный Конечная точка взаимодействия (сокет) - Обработчик получения команды управления мышью.
KeyBoardCommandReceived Частный Конечная точка взаимодействия (сокет) - Обработчик получения команды управления клавиатурой.

Примеры реализации

В качестве примера реализации рассмотрим метод, предназначенный для авторизации клиента:

public void LogIn(string Login, string Password)
{
    if (Login.Length == 0 || Password.Length == 0)
    {
        clientlogInStatus = ErrorType.EmptyData;
        return;
    }
    clientlogInStatus = ErrorType.Ok;
    clientTCP.Init(SocketType.Stream, ProtocolType.Tcp);

    RDProtocol messageLogin = CreateLogInMessage(Login, Password);
    messageLogin.commandType = CommandType.LogIn;           
        
    clientTCP.ConnectToEndPoint(serverEndpoit);       
      
    clientTCP.SendMsgSize(messageLogin);
    RDProtocol serverAnswer = null;
    clientTCP.Receive(out serverAnswer);

    if (serverAnswer.commandType == CommandType.MessageSizeAccepted)
    {              
        RDProtocol otherClientsInfo = null;
        clientTCP.Send(messageLogin);
        RDProtocol logInStatus = null;
        clientTCP.Receive(out logInStatus);
        if (logInStatus.commandType == CommandType.LogInOk)
        {
            myLogin = Login;
            int clientsInfoSize = 0;
            clientTCP.ReceiveMsgSize(out clientsInfoSize);
            RDProtocol sizeAnswer = new RDProtocol();
            sizeAnswer.commandType = CommandType.MessageSizeAccepted;
            clientTCP.Send(sizeAnswer);
            clientTCP.Receive(out otherClientsInfo, clientsInfoSize);
            ClientsInfo info = null;
            RDProtocolConvertor.ByteArrayToClientsInfo(otherClientsInfo.data, out info);
            otherClients = info.clientsList;

            Thread makeScreensThread = new Thread(new ThreadStart(ScreenMaker));
            makeScreensThread.IsBackground = true;
             makeScreensThread.Start();
                    
        }
        else if (logInStatus.commandType == CommandType.LogInError)
        {
            clientlogInStatus = ErrorType.IncorrectData;
        }
        else if (logInStatus.commandType == CommandType.ClientHasAlreadyBeenLogIn)
        {
            clientlogInStatus = ErrorType.ClientHasAlreadyBeenLogIn;
        }
    }
    else
    {
        clientlogInStatus = ErrorType.ServerError;
    }
    clientTCP.CloseConnection();           
}

Протокол взаимодействия

Для решения поставленной задачи был реализован протокол высокого уровня. Протокол состоит из двух частей – заголовка сообщения и собственно передаваемых данных. Протокол взаимодействия представлен ниже.

public enum CommandType { FindSever, LogIn, LogOut, SignIn, MoveMouse, PressKey, ShowScreen, ClientsInfo, ConnectToClient, ServerFound,  LogInOk, LogInError, MessageSize, MessageSizeAccepted, DisconnectFromClient, MouseDblClick, MouseLeftBtnCLick,MouseRightBtnCLick, MouseWheel, MouseUp, MouseDown, iAlreadyConnected, SmbConnectedToMe }                                
[Serializable]
public class RDProtocol
{       
    public CommandType commandType { get; set; }
    public byte[] data { get; set; }       
}

В зависимости от заголовка сообщения поле data сообщения, отвечающее за собственно передаваемые по сети данные, может содержать в себе разную информацию. Например, если заголовок передаваемого сообщения равен MoveMouse, что соответствует управление перемещения курсора мыши, то поле data будет представлена в виде объекта класса MouseCoordinates, конвертированного в массив байт. Класс MouseCoordinates и другие классы, описывающие возможные разновидности поля data, представлены ниже.

[Serializable]
public class MouseCoordinates
{
    public int MouseX { get; set; }
    public int MouseY { get; set; }
}
[Serializable]
public class ClientKeys
{
    public string ClientLogin { get; set; }
    public string ClientPassword { get; set; }
}
[Serializable]
public class RDEndpoint
{
    public IPAddress ipAddress { get; set; }
    public int portNumber { get; set; }
}
[Serializable]
public class ClientsInfo
{
    public List<RDEndpoint> clientsList { get; set; }
}
[Serializable]
public class ClientLoginData
{
    public ClientKeys clientKeys { get; set; }
    public RDEndpoint clientTCPEndpoint { get; set; }
}

Журналирование

Журналирование реализовано как на стороне клиента, так и на стороне сервера. Это было сделан с целью выявления причин возникновения внештатных ситуаций, а также для получения информации о работе системы, сбора статистики. Каждая строка журнала имеет следующий формат:

<Время сообщения>:<Текст сообщения>

Системные требование

Необходимо наличие .Net Framework 4.0.

Разворачивание системы

Для того, чтобы иметь возможность эксплуатации программного продукта, необходимо выполнить шаги инструкции, представленной ниже:

  • Запустить серверное приложение.
  • Запустить первое клиентское приложение на одной физической машине (возможен запуск на машине, на которой был запущен сервер).
  • Произвести успешную авторизацию первого пользователя.
  • Запустить второе клиентское приложение на машине, отличной от той, на которой было запущено первое приложение - клиент. Запуск приложений на разных машин обусловлен только лишь удобством эксплуатации программного продукта.
  • Произвести успешную авторизацию второго пользователя.
  • Выполнить подключение первого клиента ко второму или наоборот.
  • Выполнить необходимые удаленные команды.
  • Для завершения сеанса удаленного подключения отключить первого клиента от второго или наоборот, в зависимости от того, кто установил подключение.
  • Закрыть клиентские - приложения.
  • Закрыть серверное приложение.