C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сеть в Unity3D

C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение IronVolk 01 фев 2020, 12:55

Всем привет!

У меня есть C# AsyncServer - он отсылает пакеты клиенту Unity. Асинхронный Socket на Unity (статический singleton) работает (на не удаляемом объекте) на сцене (расширяет MonoBehaviour). Всё хорошо, но иногда Unity почему-то прекращает принимать пакеты, хотя они точно отправлены с сервера. Иногда принимает, иногда нет - если периодически отправлять один и тот же пакет - Unity всё таки его примет... В общем, живёт какой-то своей жизнью...

Антивирус отключал, добавлял в исключение и сервер и клиент, время задержки отправки пакетов с сервера менял (от 0 до 300 ms), порт разрешён, ставил вызов метода Recieve в Update, делал класс отдельным (не MonoBehaviour), и так далее - ничего не помогает... Unity даже не сообщает ни о каких ошибках - просто тишина... Даже не знаю куда копать...

------------------------------------------------------------------
--- Простите, почему-то не смог вставить картинку на форум. ---
--- Если что, вот ссылка на стороннем сервисе. ---
https://cdn1.savepice.ru/uploads/2020/2/1/69297b9ca8de9750e75d49cca5cfaab5-full.png
------------------------------------------------------------------

Метод Socket Receiving:

Синтаксис:
Используется csharp

private Socket _clientSocket = new Socket(
         AddressFamily.InterNetwork,
         SocketType.Stream,
         ProtocolType.Tcp
 );
 
 private byte[] _recieveBuffer = new byte[32768];
 
 private void ReceiveCallback(IAsyncResult ar) {
 
          int recieved = _clientSocket.EndReceive(ar);
 
          byte[] recData = new byte[recieved];
 
           Buffer.BlockCopy(
               _recieveBuffer,
               0,
              recData,
               0,
               recieved
         );
 
        Receive();
 }
 
 private void Receive() {      
 
         _clientSocket.BeginReceive(
             _recieveBuffer,
             0,
             _recieveBuffer.Length,
             SocketFlags.None,
             new AsyncCallback(ReceiveCallback),
             _clientSocket
         );
 
 }

 


Вот такая непонятная и раздражающая ситуация. Может кто знает, что происходит? Может мне нужно использовать Socket.ReceiveAsync(SocketAsyncEventArgs) или другой какой метод? Что вообще может происходить внутри Unity в данной ситуации - почему она по своему хотению то принимает пакеты, то нет?

Спасибо!
IronVolk
UNец
 
Сообщения: 6
Зарегистрирован: 01 фев 2020, 12:24

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение Jarico 01 фев 2020, 18:55

Пакеты могут теряться...
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение IronVolk 01 фев 2020, 21:15

Ну, это я и так понял - это, вообще-то выглядит как издевательство или страшный баг - так как если пакеты не приходят, клиент просто не знает что делать и виснит... А есть какое-нибудь решение? Почему теряются? Можно это исправить? Может однопоточный сокет надо прописать на клиенте или ещё что? Я не понимаю, почему Unity то принимает пакеты, то нет? Даже у Flash-технологии (упокой её душу) таких проблем не было вообще... Странно как-то... Читал на разных форумах об этой проблемы и на англоязычных тоже - решения не нашёл... Кто-нибудь дельное по данному вопросу может что-нибудь сказать? Спасибо!
IronVolk
UNец
 
Сообщения: 6
Зарегистрирован: 01 фев 2020, 12:24

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение Jarico 02 фев 2020, 10:52

IronVolk писал(а):Ну, это я и так понял - это, вообще-то выглядит как издевательство или страшный баг - так как если пакеты не приходят, клиент просто не знает что делать и виснит... А есть какое-нибудь решение?


Помечать каждый пакет номером

К примеру структура пакета такая

Синтаксис:
Используется csharp
struct packet(byte packet_number, byte packet_id, byte[] data)
{
byte[] data = new byte[3+data.Length]
     {
       packet_number,//номер пакета (используется byte как ид т.к. можно сделать замкнутое назначение пакетов ( packet_number++;packet_number %= byte.MaxValue; )  )
       packet_id,//ид пакета
       packet_crc,//для проверки от подделки пакетов, проверки совместимости сетевого кода
       data//данные в нагрузку
     }
}
 


1. Перед каждой отправкой нужно назначить номер пакета и его ид (вместо имени пакета)
2. Номер пакета нужен для определения потерь и задержек, одна из сторон будет предполагать что номер пакета будет на 1 больше чем предыдущий, иначе считаем что пакет потерян...
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение IronVolk 02 фев 2020, 11:15

Jarico писал(а): Помечать каждый пакет номером


Спасибо! Я так и планировал сделать в случае проблемы, но хотелось бы услышать более развёрнутый ответ, если можно... Почему это происходит и в чём смысл такой реализации в Unity? Почему пакеты должны теряться? Это что так задумано? Почему программист должен прикручивать костыли, которые будут грузить сервак и клиент лишними проверками, слать пакеты по нескольку раз, отвечать что принял пакет, увеличивать размер пакета и так далее? Что это за гадость такая? Ответьте, пожалуйста! Может я чего-то не понимаю? Может есть более изящное решение без костылей?

К тому, же - ну, определит Unity что пакет пришёл и что? Нужно будет сообщить об этом серверу... Сервак принимает пакеты по какому-то событию от клиента и даже часто без каких-либо действий от клиента... В моём случае, мне нужно будет отправлять пакет с номером от сервера до тех пор, пока клиент его не получит и не сообщит об этом - то есть мне нужно создать очередь на серваке и очередь на клиенте и обзерверы, которые будут следить за этим... Это двойная нагрузка, а то и тройная как для сервера так и для клиента...

В чём смысл в таком подходе со стороны Unity?
IronVolk
UNец
 
Сообщения: 6
Зарегистрирован: 01 фев 2020, 12:24

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение Jarico 02 фев 2020, 13:17

IronVolk писал(а):Почему это происходит и в чём смысл такой реализации в Unity? Почему пакеты должны теряться? Это что так задумано?

Это никто не задумывал... Из-за перебоев в сети, даже самых не значительных пакет может потеряться в сети (не дойти до получателя)...
Поэтому необходимо запрашивать получателя, получил ли он пакет (отправляем запрос получателю с номером отправленного пакета)

IronVolk писал(а):Почему программист должен прикручивать костыли, которые будут грузить сервак и клиент лишними проверками, слать пакеты по нескольку раз, отвечать что принял пакет, увеличивать размер пакета и так далее? Что это за гадость такая? Ответьте, пожалуйста! Может я чего-то не понимаю? Может есть более изящное решение без костылей?


А как ты думал? Отправил данные и забыл?
Решение есть: RakNet, uNet, Mirror, ENet, SmartFox, Photon, Unity Transport (alpha), SteamP2P - выбирай любое

IronVolk писал(а):К тому, же - ну, определит Unity что пакет пришёл и что? Нужно будет сообщить об этом серверу... Сервак принимает пакеты по какому-то событию от клиента и даже часто без каких-либо действий от клиента... В моём случае, мне нужно будет отправлять пакет с номером от сервера до тех пор, пока клиент его не получит и не сообщит об этом - то есть мне нужно создать очередь на серваке и очередь на клиенте и обзерверы, которые будут следить за этим... Это двойная нагрузка, а то и тройная как для сервера так и для клиента...


У тебя какое-то иное представление взаимодействия клиента и сервера...
https://metanit.com/sharp/net/
https://habr.com/ru/post/261017/
https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение IronVolk 02 фев 2020, 15:10

Спасибо за ответ! Ничего нового я не узнал, ладно. 1) Возможно, я что-то не так себе представляю - но я достаточно напилил серверов многопоточных и простых и клиентов для них - всё работает... В Flash, к примеру, (Socket TCP) никогда пакеты не теряет - ни при приёмке и при отправке - проверено 100% на многих играх... Только Unity, ёпрст, такая оригинальная (похоже)... 2) То что пакеты в сети теряются, это если под протокол UDP пилишь, насколько я знаю - но с TCP я впервые сталкиваюсь с таким геморроем... 3) Из представленных решений я использую Photon, но помимо Photon'а есть свой сервер хранения данных, где игрок также получает аутентификацию...

За совет по RakNet, Mirror, ENet, SmartFox, Unity Transport (alpha), SteamP2P спасибо, почитаю...

uNet - насколько я понял вышел новый недавно, старый был кривой, поэтому и выбрал Photon...

Насколько я знаю, Photon предоставляет площадки для серверов на основе своей технологии, но платно... У меня же свой сервер и работает отлично, только вот с Unity произошла оказия... )

Ладно, я всё понял, буду запиливать пакеты с номерами...

Отдельная благодарю за ссылочки! :)
IronVolk
UNец
 
Сообщения: 6
Зарегистрирован: 01 фев 2020, 12:24

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение Jarico 02 фев 2020, 18:07

IronVolk писал(а): Возможно, я что-то не так себе представляю - но я достаточно напилил серверов многопоточных и простых и клиентов для них - всё работает... В Flash, к примеру, (Socket TCP) никогда пакеты не теряет - ни при приёмке и при отправке - проверено 100% на многих играх...)


Протокол TCP осуществляет повторный запрос данных в случае потери данных и устраняет дублирование при получении двух копий одного пакета, гарантируя тем самым, в отличие от UDP, целостность передаваемых данных и уведомление отправителя о результатах передачи...

Протокол UDP не устанавливает соединение но отправляет дата-граммы и тут уже нужно вручную (кодом) проверять потери пакетов их порядок приёма и т.д.
В сравнении с TCP в UDP не имеется номеров пакета и они отправляются конечному соединению даже не заботясь о том придёт пакет или нет...
Github: _https://github.com/redheadgektor
Discord: Конь! Чаю!#9382 (сижу редко)
YouTube: _https://www.youtube.com/channel/UCPQ04Xpbbw2uGc1gsZtO3HQ
Telegram: _https://t.me/redheadgektor
Аватара пользователя
Jarico
Адепт
 
Сообщения: 1084
Зарегистрирован: 06 янв 2019, 17:37
Откуда: 0xDEAD
Skype: none
  • Сайт

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение IronVolk 02 фев 2020, 20:40

Ясно! Спасибо! Только я не пойму, что же мешает Unity принимать все пакеты по TCP? Дело только в том, что пакеты могут всё равно потеряться? Но тогда, почему в Flash (там тоже свой один поток и аналог Update - OnFrame) нет таких проблем? FlashPlayer'у ненужен сторонний сервер (технология), чтобы не терять пакеты от AsyncServer при передачи и приёмке, а для Unity нужен... Значит сама Unity реализована так, что не даёт другим потокам внутри себя правильно работать и мешает им какими-либо способами... В общем, думаю, что если всё так однозначно и пакеты по TCP всё равно теряются - тогда непонятно, почему это не работает в других случаях... Я несколько серверов напилил в своё время для Flash-клиентов и никогда не испытывал проблем с потерей пакетов при обмене между C# TCP AsyncServer и Flash-клиентом - и никогда не передавал кроме уникального номера пакета ещё там какие-то номера пакетов... Странно всё это! И подозрительно... Но никто не может точно объяснить, что творится в Unity и почему нельзя наладить с ней стабильную связь без потери пакетов (не используя сторонние сервисы)... Это, вообще, смахивает на специально искусственно созданную проблему в Unity, ради бабла... )
IronVolk
UNец
 
Сообщения: 6
Зарегистрирован: 01 фев 2020, 12:24

Re: C# Socket в Unity (MonoBehaviour) иногда не принимает пакеты

Сообщение IronVolk 03 фев 2020, 21:58

Прописал всё как надо, вроде работает! Пакеты не теряются. Протестировал... Спасибо за советы и ссылочки! :D Вопрос закрыт.
IronVolk
UNец
 
Сообщения: 6
Зарегистрирован: 01 фев 2020, 12:24


Вернуться в Сеть

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4