Реализация сетевого взаимодействия без cтандартного Network - Форум Игроделов
Пн, 20 Май 2024, 02:34 
 
Приветствую Вас Гость Главная | Регистрация | Вход
Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум Игроделов » UNITY3D » ОБЩИЕ ВОПРОСЫ » Реализация сетевого взаимодействия без cтандартного Network
Реализация сетевого взаимодействия без cтандартного Network
NapalmRainДата: Пн, 02 Мар 2015, 17:26 | Сообщение # 1
 
Сообщений: 473
Награды: 0
Репутация: 31
Статус: Offline
Доброго всем времени суток!

Периодически возвращаюсь к этому вопросу и вот сейчас уже совсем плотно.
Есть сервер, который слушает порт по UDP протоколу и отвечает клиент в зависимости от прилетевшей команды.
Код сервера до нельзя прост:
Код
public static void Main() {
             int recv;
             DB = new UserBD();
             byte[] data = new byte[1024];
             LogService LOG = new LogService();
             LogService.MessConstcructor Message = new LogService.MessConstcructor();
             string[] InputParams;
             Console.WriteLine("Для продолжения нажмите Enter.");
             Console.ReadLine();
             Socket mysocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
             IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 23000);
             mysocket.Bind(ipep);
             IPEndPoint sender = new IPEndPoint(IPAddress.Any, 23001);
             EndPoint Remote = (EndPoint)sender;
             Message.DateTime = DateTime.Now.ToString();
             Message.UserName = "System";
             Message.MessType = "System";
             Message.Message = "Запуск сервера";
             LOG.AddString(Message);
             Message.Message = "Попытка подключения к базам данных";
             LOG.AddString(Message);
             if (!DB.DBConnect()) {
                 Message.MessType = "Error";
                 Message.Message = "Ошибка подключения к базе MySQL";
                 LOG.AddString(Message);
             } else {
                 try {
                     Message.MessType = "Event";
                     Message.Message = "Успешное подключение к базам. Запуск сокета";
                     LOG.AddString(Message);
                     while (true) {
                         recv = mysocket.ReceiveFrom(data, ref Remote);
                         if (recv == 0) break;
                         string message = Encoding.ASCII.GetString(data, 0, recv);
                         InputParams = message.Split('|');
                         string UserID;
                         switch (InputParams[0]) {
                             case "Auth": //попытка авторизации
                    UserID = Auth(InputParams[1], InputParams[2]);
                    if (UserID!=null) {
                    Message.UserName = InputParams[1];
                    Message.MessType = "Event";
                    Message.Message = "Успешая авторизация";
                    LOG.AddString(Message);
                    data = Encoding.ASCII.GetBytes("Success|" + UserID);
                    } else {
                    Message.UserName = InputParams[1];
                    Message.MessType = "Error";
                    Message.Message = "Ошибка авторизации пользователя";
                    LOG.AddString(Message);
                    data = Encoding.ASCII.GetBytes("Failure");
                    }
                    break;
                             case "getWeaponsList":
                    Message.UserName = InputParams[1];
                    Message.MessType = "Event";
                    Message.Message = "Запрос списка Оружия";
                    LOG.AddString(Message);
                    string result = DB.getWeaponsList();
                    data = Encoding.ASCII.GetBytes("Success|" + result);
                    break;
                             case "Test":  
                    Message.UserName = "Test";
                    Message.MessType = "Event";
                    Message.Message = "Тестовый запрос";
                    LOG.AddString(Message);
                    data = Encoding.ASCII.GetBytes("Success");
                    break;
                         }
                         mysocket.SendTo(data, data.Length, SocketFlags.None, _getHost(Remote.ToString()));
                         string command = Console.ReadLine().ToString();
                     }
                 } catch (Exception ex) {
                     Console.WriteLine(ex.ToString());
                 }
             }
             Console.WriteLine("Что бы закрыть сервер, нажмите Enter");
             Console.ReadLine();
             return;
         }

В Юнити при этом создан скриптик и повешен на объект на сцене.
Код
private UdpClient udpClient;
  private IPAddress ipAddr = IPAddress.Parse("127.0.0.1");
  private IPEndPoint ipEndPoint;

  void Start () {
   byte[] bytes;
   ipEndPoint = new IPEndPoint(ipAddr, 23000);
   IPEndPoint RemoteIPEndPoint = null;
   try {
    udpClient = new UdpClient();
    udpClient.Connect(ipAddr, 23000);
    bytes = Encoding.UTF8.GetBytes("Test");
    udpClient.Send(bytes, bytes.Length);
    bytes = udpClient.Receive(ref RemoteIPEndPoint);
    string results = Encoding.UTF8.GetString(bytes);
    udpClient.Close();
    Debug.Log(results);
   } catch (ArgumentOutOfRangeException ex) {
    Debug.Log("Некорректный номер порта");
   } catch (SocketException ex) {
    Debug.Log("Порт уже используется");
   }
  }
  }

Сервер принимает запрос и сообщает о том, что таковой произошёл. Парсит его успешно, всё прекрасно.
Встаёт вопрос о том, как теперь вернуть данные в юнити... Строчка, которая теоретически должна слушать ответ приводит проект в зависание... Я понимаю, что методы работы в стандартных приложенияй, написанных на шарпе, отличаются от того, что происходит в Юнити, но всё таки хотелось бы понять, как это реализовать грамотно.

Заранее благодарю за любой совет!

Сразу отвечу на все вопросы, которые могут возникнуть: 1. Я не могу и не хочу использовать встроенную сеть Юнити,. 2. Я не хочу посмотреть в стороно Фотона и иже с ними.

Добавлено (02 Мар 2015, 17:26)
---------------------------------------------
На стороне юнити выделил два отдельных экземпляра UdpClient Sender(23000) и Listener(23001);
Sender свою задачу отрабатывает на ура, тогда как дело доходит до листенера он... Я подозреваю, что тоже отрабатывает, просто слушает без конца, в результате чего Юнити и зависает...
Может как-то создать отдельный поток, независимый от графики и работать с сетью в нём?
Если это решит вопрос, хо, хотелось бы понять, как это сделать...

 
СообщениеДоброго всем времени суток!

Периодически возвращаюсь к этому вопросу и вот сейчас уже совсем плотно.
Есть сервер, который слушает порт по UDP протоколу и отвечает клиент в зависимости от прилетевшей команды.
Код сервера до нельзя прост:
Код
public static void Main() {
             int recv;
             DB = new UserBD();
             byte[] data = new byte[1024];
             LogService LOG = new LogService();
             LogService.MessConstcructor Message = new LogService.MessConstcructor();
             string[] InputParams;
             Console.WriteLine("Для продолжения нажмите Enter.");
             Console.ReadLine();
             Socket mysocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
             IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 23000);
             mysocket.Bind(ipep);
             IPEndPoint sender = new IPEndPoint(IPAddress.Any, 23001);
             EndPoint Remote = (EndPoint)sender;
             Message.DateTime = DateTime.Now.ToString();
             Message.UserName = "System";
             Message.MessType = "System";
             Message.Message = "Запуск сервера";
             LOG.AddString(Message);
             Message.Message = "Попытка подключения к базам данных";
             LOG.AddString(Message);
             if (!DB.DBConnect()) {
                 Message.MessType = "Error";
                 Message.Message = "Ошибка подключения к базе MySQL";
                 LOG.AddString(Message);
             } else {
                 try {
                     Message.MessType = "Event";
                     Message.Message = "Успешное подключение к базам. Запуск сокета";
                     LOG.AddString(Message);
                     while (true) {
                         recv = mysocket.ReceiveFrom(data, ref Remote);
                         if (recv == 0) break;
                         string message = Encoding.ASCII.GetString(data, 0, recv);
                         InputParams = message.Split('|');
                         string UserID;
                         switch (InputParams[0]) {
                             case "Auth": //попытка авторизации
                    UserID = Auth(InputParams[1], InputParams[2]);
                    if (UserID!=null) {
                    Message.UserName = InputParams[1];
                    Message.MessType = "Event";
                    Message.Message = "Успешая авторизация";
                    LOG.AddString(Message);
                    data = Encoding.ASCII.GetBytes("Success|" + UserID);
                    } else {
                    Message.UserName = InputParams[1];
                    Message.MessType = "Error";
                    Message.Message = "Ошибка авторизации пользователя";
                    LOG.AddString(Message);
                    data = Encoding.ASCII.GetBytes("Failure");
                    }
                    break;
                             case "getWeaponsList":
                    Message.UserName = InputParams[1];
                    Message.MessType = "Event";
                    Message.Message = "Запрос списка Оружия";
                    LOG.AddString(Message);
                    string result = DB.getWeaponsList();
                    data = Encoding.ASCII.GetBytes("Success|" + result);
                    break;
                             case "Test":  
                    Message.UserName = "Test";
                    Message.MessType = "Event";
                    Message.Message = "Тестовый запрос";
                    LOG.AddString(Message);
                    data = Encoding.ASCII.GetBytes("Success");
                    break;
                         }
                         mysocket.SendTo(data, data.Length, SocketFlags.None, _getHost(Remote.ToString()));
                         string command = Console.ReadLine().ToString();
                     }
                 } catch (Exception ex) {
                     Console.WriteLine(ex.ToString());
                 }
             }
             Console.WriteLine("Что бы закрыть сервер, нажмите Enter");
             Console.ReadLine();
             return;
         }

В Юнити при этом создан скриптик и повешен на объект на сцене.
Код
private UdpClient udpClient;
  private IPAddress ipAddr = IPAddress.Parse("127.0.0.1");
  private IPEndPoint ipEndPoint;

  void Start () {
   byte[] bytes;
   ipEndPoint = new IPEndPoint(ipAddr, 23000);
   IPEndPoint RemoteIPEndPoint = null;
   try {
    udpClient = new UdpClient();
    udpClient.Connect(ipAddr, 23000);
    bytes = Encoding.UTF8.GetBytes("Test");
    udpClient.Send(bytes, bytes.Length);
    bytes = udpClient.Receive(ref RemoteIPEndPoint);
    string results = Encoding.UTF8.GetString(bytes);
    udpClient.Close();
    Debug.Log(results);
   } catch (ArgumentOutOfRangeException ex) {
    Debug.Log("Некорректный номер порта");
   } catch (SocketException ex) {
    Debug.Log("Порт уже используется");
   }
  }
  }

Сервер принимает запрос и сообщает о том, что таковой произошёл. Парсит его успешно, всё прекрасно.
Встаёт вопрос о том, как теперь вернуть данные в юнити... Строчка, которая теоретически должна слушать ответ приводит проект в зависание... Я понимаю, что методы работы в стандартных приложенияй, написанных на шарпе, отличаются от того, что происходит в Юнити, но всё таки хотелось бы понять, как это реализовать грамотно.

Заранее благодарю за любой совет!

Сразу отвечу на все вопросы, которые могут возникнуть: 1. Я не могу и не хочу использовать встроенную сеть Юнити,. 2. Я не хочу посмотреть в стороно Фотона и иже с ними.

Добавлено (02 Мар 2015, 17:26)
---------------------------------------------
На стороне юнити выделил два отдельных экземпляра UdpClient Sender(23000) и Listener(23001);
Sender свою задачу отрабатывает на ура, тогда как дело доходит до листенера он... Я подозреваю, что тоже отрабатывает, просто слушает без конца, в результате чего Юнити и зависает...
Может как-то создать отдельный поток, независимый от графики и работать с сетью в нём?
Если это решит вопрос, хо, хотелось бы понять, как это сделать...


Автор - NapalmRain
Дата добавления - 02 Мар 2015 в 17:26
ЛевшаДата: Пн, 02 Мар 2015, 17:34 | Сообщение # 2
Черный Волк
 
Сообщений: 7257
Награды: 30
Репутация: 3313
Статус: Offline
Как минимум в корутину вынести.
Насчет встроенной сети - зря...
smile


X.cor.R (Prologue)
 
СообщениеКак минимум в корутину вынести.
Насчет встроенной сети - зря...
smile

Автор - Левша
Дата добавления - 02 Мар 2015 в 17:34
NapalmRainДата: Пн, 02 Мар 2015, 17:47 | Сообщение # 3
 
Сообщений: 473
Награды: 0
Репутация: 31
Статус: Offline
Левша, благодарю за наводку, нашёл вот такую статейку, надеюсь, поможет...
Перестал наследоваться от MonoBehaviour, всю логику вынес в отдельный класс. буду пробовать получать значения с сервера через него.

А по поводу встроенной сети. Она, увы, хоть и облегчает жизнь, но подразумевает, что сервер так же должен быть сделан на Юнити. Это, возможно, и не плохой вариант, так как позволяет просчитывать на нём хотя бы туже физику, но блин... Сервер с графической оболочкой? Я просто себе очень слабо представляю характеристики машины, на которой он должен будет работать... Это ж мало того, что там будет прорва оперативки и процессорных ядер, придётся ещё туда же впихивать видеокарту... У меня в голове это не очень укладывается smile

Добавлено (02 Мар 2015, 17:47)
---------------------------------------------
Левша, а, если не секрет, в чём преимущество использования корутин, перед потоками?

 
СообщениеЛевша, благодарю за наводку, нашёл вот такую статейку, надеюсь, поможет...
Перестал наследоваться от MonoBehaviour, всю логику вынес в отдельный класс. буду пробовать получать значения с сервера через него.

А по поводу встроенной сети. Она, увы, хоть и облегчает жизнь, но подразумевает, что сервер так же должен быть сделан на Юнити. Это, возможно, и не плохой вариант, так как позволяет просчитывать на нём хотя бы туже физику, но блин... Сервер с графической оболочкой? Я просто себе очень слабо представляю характеристики машины, на которой он должен будет работать... Это ж мало того, что там будет прорва оперативки и процессорных ядер, придётся ещё туда же впихивать видеокарту... У меня в голове это не очень укладывается smile

Добавлено (02 Мар 2015, 17:47)
---------------------------------------------
Левша, а, если не секрет, в чём преимущество использования корутин, перед потоками?


Автор - NapalmRain
Дата добавления - 02 Мар 2015 в 17:47
seamanДата: Пн, 02 Мар 2015, 18:57 | Сообщение # 4
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Цитата
если не секрет, в чём преимущество использования корутин, перед потоками?

В простоте использования. А так - это совсем не поток...
Цитата
Может как-то создать отдельный поток, независимый от графики и работать с сетью в нём?
Если это решит вопрос, хо, хотелось бы понять, как это сделать...

Как обычно при работе с потоками. Единственно - из своего потока нельзя использовать Unity методы. Т.е. типа - результаты нужно куда то складывать, откуда в Юнити можно будет их получить...
 
Сообщение
Цитата
если не секрет, в чём преимущество использования корутин, перед потоками?

В простоте использования. А так - это совсем не поток...
Цитата
Может как-то создать отдельный поток, независимый от графики и работать с сетью в нём?
Если это решит вопрос, хо, хотелось бы понять, как это сделать...

Как обычно при работе с потоками. Единственно - из своего потока нельзя использовать Unity методы. Т.е. типа - результаты нужно куда то складывать, откуда в Юнити можно будет их получить...

Автор - seaman
Дата добавления - 02 Мар 2015 в 18:57
seamanДата: Пн, 02 Мар 2015, 19:54 | Сообщение # 5
Гуру
 
Сообщений: 1748
Награды: 10
Репутация: 660
Статус: Offline
Вообще, если интересно - смотри клиент Фотона. Он прекрасно декомпилируется. Там все построено на System.Net System.Net.Sockets
А потоки используются в основном для асинхронности послания и приема информации
 
СообщениеВообще, если интересно - смотри клиент Фотона. Он прекрасно декомпилируется. Там все построено на System.Net System.Net.Sockets
А потоки используются в основном для асинхронности послания и приема информации

Автор - seaman
Дата добавления - 02 Мар 2015 в 19:54
NapalmRainДата: Вт, 03 Мар 2015, 01:27 | Сообщение # 6
 
Сообщений: 473
Награды: 0
Репутация: 31
Статус: Offline
seaman, благодарю. Попробую Прочитал про корутины, думаю, они всё же не совсем то, что мне нужно. Как вернуть из асинхронного потока данные я придумаю. Но, может ещё иначе решу вопрос...
 
Сообщениеseaman, благодарю. Попробую Прочитал про корутины, думаю, они всё же не совсем то, что мне нужно. Как вернуть из асинхронного потока данные я придумаю. Но, может ещё иначе решу вопрос...

Автор - NapalmRain
Дата добавления - 03 Мар 2015 в 01:27
ЛевшаДата: Вт, 03 Мар 2015, 11:14 | Сообщение # 7
Черный Волк
 
Сообщений: 7257
Награды: 30
Репутация: 3313
Статус: Offline
Цитата NapalmRain ()
но блин... Сервер с графической оболочкой?

Совсем не обязательно... как напишешь - так и будет.


X.cor.R (Prologue)
 
Сообщение
Цитата NapalmRain ()
но блин... Сервер с графической оболочкой?

Совсем не обязательно... как напишешь - так и будет.

Автор - Левша
Дата добавления - 03 Мар 2015 в 11:14
Форум Игроделов » UNITY3D » ОБЩИЕ ВОПРОСЫ » Реализация сетевого взаимодействия без cтандартного Network
  • Страница 1 из 1
  • 1
Поиск:
Загрузка...

Game Creating CommUnity © 2009 - 2024