Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
 Аватар для nnnikotinnn995
7 / 7 / 4
Регистрация: 07.07.2011
Сообщений: 583

Real time на Socket (udp)

06.12.2019, 17:45. Показов 1558. Ответов 3

Студворк — интернет-сервис помощи студентам
Здравствуйте. Не знаю почему, но способ реализации Real time игры всегда остается в "ТАЙНЕ". В гугл поиске, так же как в документации можно найти только подсказки и строительный материал (методы, классы...), а как из него построить дом - нет готового решения. Поэтому я решил попробовать сам это сделать и обменяться с Вами опытом. Раньше делал это на java.nio и все работало на TCP Тест NIO (simple code) . Нашел много общего на C# Socket. Идея в том, чтобы читать/писать данные в одном потоке, а исполнять их в другом. От простого к сложному.
Сервер должен выполнять роль "стрелочника", у него нет необходимости подключатся к кому нибудь из клиентов. Просто получает данные, исполняет их и отправляет тем, кто в одной группе;
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class Program{
        static int localPort=8005; // порт приема сообщений
        static Socket listeningSocket;static string ServerAddress = "192.168.0.103";
 
        static void Main(string[] args){
            try
            {
                listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                Task listeningTask = new Task(Listen);
                listeningTask.Start();
                Console.WriteLine("Сервер запущен;");
                Console.ReadLine();
            } catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            } finally
            {
                Close();
            }
        }
        // поток для приема подключений
        private static void Listen()
        {
            try
            {
                //Прослушиваем по адресу
                IPEndPoint localIP = new IPEndPoint(IPAddress.Parse(ServerAddress), localPort);
                listeningSocket.Bind(localIP);//связываем сокет с узлом 
 
                while (true){
                    // получаем сообщение
                    StringBuilder builder = new StringBuilder();
                    int bytes = 0; // количество полученных байтов
                    byte[] data = new byte[256]; // буфер для получаемых данных
 
                    //адрес, с которого пришли данные
                    EndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);
                    do
                    {
                        bytes = listeningSocket.ReceiveFrom(data, ref remoteIp);
                        builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
                    }
                    while (listeningSocket.Available > 0);
                    // получаем данные о подключении
                    IPEndPoint remoteFullIp = remoteIp as IPEndPoint;//listeningSocket.Connect(remoteFullIp);
                    // выводим сообщение
                    Console.WriteLine("{0}:{1} - {2}", remoteFullIp.Address.ToString(),
                                                    remoteFullIp.Port,";"+ builder.ToString());
//EndPoint remotePoint = new IPEndPoint(remoteFullIp.Address,remoteFullIp.Port);
data = Encoding.Unicode.GetBytes("сообщение получено");
                    //в будущем здесь будем запускать новый поток на исполнение пакетов
                    //отправляем клиенту обратно
                  listeningSocket.SendTo(data, remoteIp);
                }
            } catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            } finally
            {
                Close();
            }
        }
        // закрытие сокета
        private static void Close()
        {
            if (listeningSocket != null)
            {
                listeningSocket.Shutdown(SocketShutdown.Both);
                listeningSocket.Close();
                listeningSocket = null;
            }
        }
    }
На клиенте связывать с узлом не нужно, и как пишут конектить сокет с сервером тоже не нужно, но у меня почему то без connect ноутбук не может по локальной сети увидеть стационар по вайфай. Может надо что то в настройках сети сделать?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class Program
    {
        static int remotePort = 8005;
        static Socket listeningSocket; static string ServerAddress = "192.168.0.103";
 
        static void Main(string[] args)
        { 
            try
            {
                listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 
                IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(ServerAddress), remotePort);
                //ОБЯЗАТЕЛЬНО, иначе не чего не придет/отправится
                listeningSocket.Connect(ipPoint);
                
                Task listeningTask = new Task(Listen);listeningTask.Start();
                Console.WriteLine("Введите сообщение и нажмите Enter");
                // отправка сообщений на разные порты
                while (true)
                {
                    string message = Console.ReadLine();
                    byte[] data = Encoding.Unicode.GetBytes(message);
                    listeningSocket.Send(data); 
                    //listeningSocket.SendTo(data, ipPoint); можно и так, но зачем?
                }
            } catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            } finally
            {
                Close();
            }
        }
        // поток для приема подключений
        private static void Listen()
        {
            try {
                while (true){
                    // получаем сообщение
                    StringBuilder builder = new StringBuilder();
                    int bytes = 0; // количество полученных байтов
                    byte[] data = new byte[256]; // буфер для получаемых данных
 
                    //адрес, с которого пришли данные
                    EndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);
                    do
                    {
                        bytes = listeningSocket.ReceiveFrom(data, ref remoteIp);
                        builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
                    }
                    while (listeningSocket.Available > 0);
                    // получаем данные о подключении
                    IPEndPoint remoteFullIp = remoteIp as IPEndPoint;
 
                    // выводим сообщение
                    Console.WriteLine("{0}:{1} - {2}", remoteFullIp.Address.ToString(),
                    remoteFullIp.Port, "senrven;" + builder.ToString());
                }
            } catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            } finally
            {
                Close();
            }
        }
        // закрытие сокета
        private static void Close()
        {
            if (listeningSocket != null)
            {
                listeningSocket.Shutdown(SocketShutdown.Both);
                listeningSocket.Close();
                listeningSocket = null;
            }
        }
    }
Сначала нужно запустить сервер, потом клиент (естественно). Все работает. Но как всегда наверняка могут быть какие то подводные камни (то утечка памяти, то еще чего). Во первых в сети почему то рекомендуют посылать не через Send(data), а через SendTo(data, remoteIp);. Почему? Чем Send хуже SendTo?
Это только начало, но хотелось бы услышать Ваши замечания (я новичок, может чего то упустил или сделал ни так как надо).
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
06.12.2019, 17:45
Ответы с готовыми решениями:

Использовать udp socket в com объекте
Я - блондинка, ударившаяся в программирование, которой необходима Ваша помощь, уважаемые знатоки!! Этим я попыталась оправдать глупость...

Real time clock error - Check date and time setting
Всех приветствую! Ноутбук Lenovo b590, после помывки и просушки мат платы, при включении стал выдавать сею картину(на скриншоте). В...

Out of memory in Real-Time
При нажатии на кнопку Connect To Target возникает ошибка: Error occurred while executing External Mode MEX-file 'rtwinext': Not enough...

3
 Аватар для nnnikotinnn995
7 / 7 / 4
Регистрация: 07.07.2011
Сообщений: 583
07.12.2019, 13:39  [ТС]
без коннекта сокета
C#
1
2
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(ServerAddress), remotePort);
listeningSocket.Connect(ipPoint);
метод получения сообщений
C++
1
bytes = listeningSocket.ReceiveFrom(data, ref remoteIp);
вызывает исключение - "перед этой операцией необходимо вызвать Bind". Жду опровержения, но похоже со мной ни кто спорить не будет.
0
 Аватар для nnnikotinnn995
7 / 7 / 4
Регистрация: 07.07.2011
Сообщений: 583
08.12.2019, 08:58  [ТС]
Я тестирую на локальном внутреннем адресе который периодически меняется (то 192.168.0.103 то 192.168.0.100 и т.д.). Приходится постоянно на сервере его узнавать и менять при повторном запуске
C#
1
2
3
4
static string ServerAddress = "192.168.0.103";
//Прослушиваем по адресу
                IPEndPoint localIP = new IPEndPoint(IPAddress.Parse(ServerAddress), localPort);
                listeningSocket.Bind(localIP);//связываем сокет с узлом
Можно ли на сервере автоматически узнать внутренний/внешний адрес в коде? В классе IPAddress не чего не нашел.
0
 Аватар для nnnikotinnn995
7 / 7 / 4
Регистрация: 07.07.2011
Сообщений: 583
10.12.2019, 10:54  [ТС]
А как Вы думаете, если нужно сначала к одному серверу подключить клиента, получить от него данные, потом к другому серверу так же,то можно ли сокет не обнулять после отключения от первого сервера
C#
1
2
3
4
5
6
7
8
9
10
// закрытие сокета
        private static void Close()
        {
            if (listeningSocket != null)
            {
                listeningSocket.Shutdown(SocketShutdown.Both);
                listeningSocket.Close();
                listeningSocket = null;
            }
        }
а вместо этого просто дисконектить его от старого и подключить к новому серверу
C#
1
2
3
4
5
 listeningSocket.Disconnect(true);
//listeningSocket=new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(NewServerAddress), remotePort);
            //ОБЯЗАТЕЛЬНО, иначе не чего не придет/отправится
            listeningSocket.Connect(ipPoint);
Или перед подключением к новому серверу его нужно закрывать?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.12.2019, 10:54
Помогаю со студенческими работами здесь

Real time debugging
Каким образом это можно реализовать в XNA? Что я хочу, так это следующее: при компиляции проекта должно запускаться два окна - игра и окно...

Real Time Counter
Всем привет! С AVR работаю недавно, по этому есть пару вопросов и советов. Возник вопрос по поводу таймера реального времени, а именно...

Сетевые real-time игры
Здравствуйте, в универе дали курсач по ООП свой проект. Хотел попробовать написать сетевую real-time игру, но хотел бы уточнить один...

Real-time отладка с ST-Link
Подскажите, давно не занимался STM-ми, а щас потребовалось: имеется ли возможность просматривать хотябы переменные и регистры без остановки...

Real-time возможности в онлайн игре
Всем доброго времени суток! :) Подскажите, как сделать некоторые real-time возможности в онлайн-стратегии, например сбор ресурсов. Он...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Загрузка PNG-файла с альфа-каналом с помощью библиотеки SDL3_image на Android
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru