Автоматическое подключение по локальной сети

исходники++ / Язык программирования C# / Автоматическое подключение по локальной сети
Оглавление:
  1. Комфортность автоподключения
  2. Широковещательные (broadcast) адреса
  3. Кратко о работе TCP
  4. Кратко о работе UDP
  5. Алгоритм автоматического подключения по сети
  6. Сетевой чат с автоматическим подключением
  7. Состав классов сетевого чата с авто-подключением
  8. Модуль UDP сервиса
  9. Исходный код сетевого чата с автоматическим подключением по сети

Комфортность автоподключения

Сложность поиска IP-адреса

Создавая сетевое приложение, особенно игровое, часто возникает желательность автоматического подключения приложений друг к другу.

Часто в описании подключения сетевых программ требуется ввод сетевых координат: IP-адреса и номера порта сервера. Непродвинутым пользователям (чайникам 😊) сложно разбираться в IP адресах, номерах портов и их поисках на собственных компьютерах.

Для пользователей, и не только чайникам, было бы очень комфортно при наличии возможности самостоятельного подключения сетевых программ друг к другу. Какой сетевой протокол TCP или UDP использовать для таких программ и как построить алгоритм работы автоматического подключения по сети? Один из ответов на этот вопрос описан в исходнике прикрепленного приложения-чата.

Широковещательные (broadcast) адреса

Широковещательные сообщения

Широковещательный адрес (broadcast) – это зарезервированный условный IP-адрес, предназначенный для отправки сообщений всем участникам сети. Широковещательные адреса для разных подсетей имеют виды - 255.255.255.255, 192.255.255.255, 192.168.255.255, 192.168.1.255. Соответственно широковещательный адрес 255.255.255.255 позволяет отправлять сообщений клиентам всех сетей, 192.168.1.255 только клиентам сети 192.168.1.0.

Широковещательные адреса вычисляются на основе маски подсети и IP-адреса устройства. Например:
маска подсети 255.255.0.0 и адрес устройства 172.25.14.23 создают широковещательный адрес 172.25.255.255 для сети 172.25.0.0,
маска 255.255.255.0 и IP-адрес 192.168.0.34 создают broadcast-адрес 192.168.0.255 для сети 192.168.0.0. Отправка широковещательных сообщений не предполагает получения обратных ответов.

Кратко о работе TCP

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

Создавая сетевые приложения, работающие по протоколу TCP для соединения необходимо предварительное точное знание IP-адреса и номера порта сервера. TCP не допускает отправку сообщений на широковещательные (broadcast) адреса из-за необходимости предварительного подключения.

Кратко о работе UDP

Организация связи по протоколу UDP не требует факта установления предварительного соединения. Клиент UDP может отправлять сообщения по определенному адресу и номеру порта, даже не имея информации о существовании сервера. UDP не гарантирует доставку и последовательность сообщений, но гарантирует целостность полученного сообщения.

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

Алгоритм автоматического подключения по сети

Используя теоретические знания о свойствах протоколов TCP, UDP и широковещательных адресов можно построить алгоритм автоматического подключения сетевых программ друг к другу. Для этого лучше использовать «команду» протоколов: UDP – для поиска клиентов в сети, TCP – для установления надежного соединения между сетевыми приложениями. Чтобы не засорять локальную сеть, широковещательные адреса отсылать разово, по действию пользователя.

Алгоритм автоматического подключения сетевых программ:
  • Вычисление широковещательного адреса на основе маски подсети и IP-адреса устройства.
  • Поиск сервера в сети, если сервер не обнаружен, то создается сервер для возможных подключений.
  • Если сервер обнаружен, то приложение подключается к нему как клиент.
  • С найденными родственными приложениями создается канал обмена сообщениями по протоколу TCP.

Сетевой чат с автоматическим подключением

 Приложение сетевого чата
Приложение сетевого чата

На основе вышеописанного алгоритма создано сетевое приложение-чат на C# Windows Forms с автоматическим подключением друг к другу. После авто-подключения чат начинает работать и можно обмениваться сообщениями с клиентами.

Процесс подключения к возможным клиентам в сети активируется после нажатия кнопки Подключение и если клиентов в сети нет, то создается сервер для прослушивания подключений. При наличии сервера в сети приложение-чат подключается к серверу.

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

Кнопка Служебные данные показывает окно со списком последовательности значимых действий сетевого приложения. Служебные данные пригодятся при модификации и отладки приложения.

Состав классов сетевого чата с авто-подключением

Состав классов сетевого чата с авто-подключением
Состав классов сетевого чата

Исходник сетевого чата с авто-подключением состоит из двух форм и нескольких вспомогательных классов.

FormMain – основной класс-форма, визуальный интерфейс управления чатом.

FormServiceData – класс-форма для вывода служебных данных: действий, производимых сервисами UDP и TCP. Необходима для визуализации последовательности действий.

UDPModule – UDP сервис поиска сервера и клиентов в сети.

BytesPack – класс сериализации объекта в массив байтов и обратно.

Common – класс общих данных приложения

DataClient – класс данных клиента, служит для обмена информацией между клиентами, рассылаемой модулем UDP.

DataServer – класс хранения IP и номера порта сервера TCP.

IPMacnine и IPAddressExtensions – классы для вычисления широковещательного адреса сети текущей машины.

MyList – класс производный от типизированного списка List, расширяет стандартный список событием изменения списка при удалении и добавлении элементов.

Utils – вспомогательный класс статических методов, обеспечивающих безопасное управление интерфейсными элементами форм из других потоков.

Модуль UDP сервиса

UDPModule – функциональный сетевой модуль, работающий по протоколу UDP для поиска сервера и клиентов в сети, принадлежащих только данному сетевому приложению. Класс UDPModule обеспечивает надежность работы обмена датаграммами в случае занятости рабочих портов сторонними приложениями.

Работа по протоколу UDP выделена в отдельный класс и общение с главной формой происходит посредством событий. Например, при обнаружении в сети сервера для клиентов чата генерируется соответствующее событие и данные передаются в обработчик события сервиса TCP. Связь с другими классами, создаваемая на основе событий, упрощает внедрение программного кода UDPModule в любое сетевое приложение, где требуется автоматическое подключение по сети.

Краткий листинг программного кода модуля UDPModule:
internal class UDPModule
{
    #region Определение полей и свойств

    // Определение делегата для события получения данных сервера.
    public delegate void ReceivedServerDataEventHandler(DataServer serverTCP);
    public event ReceivedServerDataEventHandler? ReceivedServerData;

    // Определение делегата для события изменения состояния приложения.
    public delegate void StatusEventHandler(string status);
    public event StatusEventHandler? Status;

    // Определение делегата для события изменения режима работы приложения.
    public delegate void ModeAppEventHandler(int mode);
    public event ModeAppEventHandler? ModeApplication;


    // Хранение UDP данных родственных приложений.
    public List _clientsUDP = new();

    ...

    #endregion

    public UDPModule(FormServiceData serviceData, int idClient)
    {
        _serviceData = serviceData;

        // Получение идентификатора клиента.
        _dataClient.id = idClient;
        Utils.TextToLabels(_serviceData.lblClientID, _dataClient.id.ToString());

        // Сохранение идентификатора приложения в
        // данных клиента для обмена по сети.
        _dataClient.idApplication = Common.IdApplication;
    }

    #region Инициализация UDP сервиса

    // Иициализация сервиса обмена широковещательными
    // сообщениями по протоколоу UDP в пределах одноранговой сети.
    public bool InitUDP()
    {
        ...

        // Чтобы основной поток приложения не блокировался,
        // для извлечения сообщений запускаем дополнительный поток.
        ThreadStart tstart = new(ReceiveUDP);
        Thread threadReceiveUDP = new(tstart)
        {
            // Делаем поток фоновым, чтобы при закрытии приложения
            // он автоматически прекращал свою работу.
            IsBackground = true
        };
        threadReceiveUDP.Start();

        // Успешная инициализация UDP сервиса.
        return true;
    }

    #endregion

    #region Получение UDP-датаграмм

    // Прием датаграмм UDP.
    private void ReceiveUDP()
    {
        // 
        while (_udp != null)
        {
            IPEndPoint? remote = null;
            byte[] bytes = _udp.Receive(ref remote);

            // Проверка родственного приложения, 
            // если прошел проверку включаем в группу
            // и отвечаем ему.
            // Свои сообщения игнорируем.
            if (BytesPack.FromBytes(bytes) is DataClient recvDataClient &&
                recvDataClient.idApplication == Common.IdApplication &&
                recvDataClient.id != _dataClient.id)
            {
                // Заполняем и обновляем список клинтов.
                AddListClientsUDP(recvDataClient);

                // Обработка полученной датаграммы
                switch (recvDataClient.typeMessage)
                {
                    ...
                }
            }
        }
    }

    #endregion

    #region Вспомогательные методы для UDP-сервиса

    // Добавляем нового клиента в списко клиентов UDP.
    void AddListClientsUDP(DataClient dataClient)
    {
        // Если такой клиент уже есть в списке, то обновляем его данные.
        DataClient? p = _clientsUDP.FirstOrDefault(p => p.id == dataClient.id);
        if (p != null)
        {
            _clientsUDP.Remove(p);
        }
        _clientsUDP.Add(dataClient);

        ...
    }

    public bool ServerSearch()
    {
        // Подготавливаем широковещательный адрес текущей машины.
        IPAddress thisBroadcast = IPMacnine.GetBroadcastIP();

        DataClient dataClient = _dataClient;
        // Указываем тип сообщения - поиск сервера.
        dataClient.typeMessage = TypeMessage.ServerSearch;

        // Преобразуем объект в байты.
        byte[] bytes = BytesPack.ToBytes(dataClient);

        // Отправка сообщения на все номера портов, поскольку 
        // есть вероятность занятости первого порта в списке.
        for (int i = 0; i < Common.Ports.Length; i++)
        {
            // Пример: широковещательный адрес для маски подсети 255.255.255.0
            // IPEndPoint ep = new(IPAddress.Parse("192.168.1.255"), номер порта);
            IPEndPoint ep = new(thisBroadcast, Common.Ports[i]);
            SendDatagramUDP(bytes, ep);
        }

        return _sentFirstRequestServer;
    }

    // Ответ отправляется только клиенту запросившему сервер.
    void ResponseServerSearch(string ip, int port)
    {
        DataClient dataClient = _dataClient;

        // Указываем соответствующий тип сообщения.
        dataClient.typeMessage = TypeMessage.ResponseServerSearch;

        byte[] bytes = BytesPack.ToBytes(dataClient);
        IPEndPoint ep = new(IPAddress.Parse(ip), port);
        SendDatagramUDP(bytes, ep);
    }

    public static void SendDatagramUDP(byte[] bytes, IPEndPoint ep)
    {
        using UdpClient udp = new();
        udp.Connect(ep);
        udp.Send(bytes, bytes.Length);
    }

    // Определение режима работы приложения: сервер или клиент.
    public bool DoServer()
    {
        // Определения сервера среди ответов других клиентов.
        bool doServer = !_clientsUDP.Where(e => e.id != _dataClient.id && e.mode == 1).Any();

        // Указание созлавать сервер, в противном случае клиента.
        if (doServer == true)
        {
            ...
        }
        else
        {
            ...
        }

        // Генерация события изменения статуса приложения.
        OnModeApplication(_dataClient.mode);

        return doServer;
    }

    #endregion

    #region Методы вызова событий генерируемых сервисом UDP

    protected virtual void OnReceivedServerData(DataServer serverTCP)
    {
        ReceivedServerData?.Invoke(serverTCP);
    }

    protected virtual void OnStatus(string status)
    {
        Status?.Invoke(status);
    }

    protected virtual void OnModeApplication(int mode)
    {
        ModeApplication?.Invoke(mode);
    }

    #endregion
}

Исходный код сетевого чата с автоматическим подключением по сети

Исходник написан на языке C# в MS Visual Studio 2022, приложение Windows Forms .NET6. Исходный код подробно комментирован, описан общий смысл работы методов, свойств и полей классов. Функциональность автоматического подключения приложения-чата можно легко перенести на другую сетевую игру или прикладную программу.

Доступ к исходнику

Для скачивания исходника необходимо ввести код:

Оплата кода доступа

Стоимость доступа к исходнику - 330 ₽

Сразу после оплаты активируется ссылка на скачивание исходника. Также, на указанный e-mail высылается код доступа. Код действует 2 суток. Внимание: письмо может попасть в папку спама.

Скачать исходник

Тема: «Автоматическое подключение по локальной сети» Чат с автоподключением💾WFAutoConnect-vs17.zipРазмер:123 КбайтЗагрузки:12