У меня есть вопрос по поводу UDP. Для контекста, я работаю над игрой в реальном времени.
Я довольно много читал о различиях между UDP и TCP, и мне кажется, что я их хорошо понимаю, но есть одна статья, которая никогда не была правильной, и это надежность и, в частности, признание . Я понимаю, что UDP не обеспечивает надежности по умолчанию (то есть пакеты могут быть отброшены или доставлены не по порядку). Когда требуется некоторая надежность, решение, которое я видел (что имеет концептуальный смысл), заключается в использовании подтверждений (т. Е. Сервер отправляет пакет клиенту, а когда клиент получает это сообщение, он отправляет подтверждение на сервер) ,
Что происходит, когда подтверждение сбрасывается?
В приведенном выше примере (один сервер отправляет пакет одному клиенту), сервер обрабатывает потенциальную потерю пакетов, повторно отправляя пакеты каждый кадр, пока не будут получены подтверждения для этих пакетов. Вы все еще можете столкнуться с проблемами пропускной способности или неупорядоченными сообщениями, но только с точки зрения потери пакетов сервер покрыт.
Однако, если клиент отправляет подтверждение, которое никогда не приходит, у сервера не останется иного выбора, кроме как в конечном итоге прекратить отправку этого сообщения, что может прервать игру, если потребуется информация, содержащаяся в этом пакете. Вы можете использовать аналогичный подход к серверу (т.е. продолжать отправлять подтверждения, пока вы не получите подтверждение для подтверждения?), Но при таком подходе вы будете циклически возвращаться назад и вперед навсегда (поскольку вам потребуется подтверждение для подтверждения для подтверждения и так далее).
Я чувствую, что моя основная логика здесь верна, что оставляет мне два варианта.
- Отправьте один пакет подтверждения и надейтесь на лучшее.
- Отправьте несколько пакетов подтверждения (возможно, 3-4) и надейтесь на лучшее, предполагая, что не все они будут отброшены.
Есть ли ответ на эту проблему? Я что-то принципиально неправильно понимаю? Есть ли какая-то гарантия использования UDP, о которой я не знаю? Я не решаюсь продвигаться вперед со слишком большим количеством сетевого кода, пока не почувствую себя комфортно, если моя логика будет здравой.
источник
Ответы:
Это форма проблемы двух генералов , и вы правы - никакого количества повторов недостаточно для полной гарантии получения.
На практике в играх обычно существует временной интервал, за которым информация на самом деле не имеет значения, даже если она технически надежно поступает. Подобно тому, как вы узнали, что у вас был идеальный выстрел в голову 2 секунды назад - игроку уже слишком поздно использовать эту информацию.
Если ваша потеря пакетов настолько высока, что вы не можете регулярно получать необходимую информацию через узкое окно реакции, то для игры в реальном времени вам лучше будет пнуть игрока и попытаться найти для них лучшее соответствие в другом месте, чем продолжайте попытки отправить пакет для эмуляции надежного соединения.
Из-за этого некоторые системы репликации игр вообще пропускают подтверждения и повторы и предпочитают просто спамить самое новое обновление как можно чаще. Если кто-то упал или опоздал, слишком плохо, пропустите его, возьмите следующий и продолжайте, полагаясь на системы прогнозирования и интерполяции, чтобы сгладить разрыв и минимизировать икоты, видимые для игрока.
Я внезапно хочу начать называть это «Реплика Симба» за то, что она игнорирует проблемы в прошлом и пытается жить в настоящем моменте. ;)
Гибридное решение состоит в том, чтобы поспешить с отправкой нового обновления И (поскольку обновления состояния игры часто бывают довольно маленькими / сжимаемыми ), а также упаковывать последнее обновление, а может быть, и предыдущее ... Так что на всякий случай клиент пропустил их Вам не нужно ждать полного обхода, чтобы выяснить и исправить это. В большинстве случаев клиент уже видел это, поэтому таким образом существуют избыточные данные, но задержка для исправления пропущенного сообщения ниже. Обновления клиента могут включать в себя порядковый номер самого последнего последовательного обновления, которое они видели, поэтому вы можете быть минимально консервативными с тем, сколько старых обновлений вы включите в следующий пакет обновлений.
Вы также можете реализовать двухуровневую систему в качестве другого типа гибрида, в котором кратковременное состояние реплицируется ненадежным быстрым способом, а долговременное состояние надежно синхронизируется, используя TCP или собственную реализацию надежности с высокой повторной попыткой. сосчитать. Это становится более сложным в управлении, поскольку у вас есть две системы обмена сообщениями, которые нужно обслуживать, и эти два снимка могут быть не синхронизированы друг с другом, добавляя совершенно новый класс пограничного случая.
источник
Подход, который использует TCP, заключается в том, что отправитель будет повторно отправлять пакет, пока не получит подтверждение. Получатель будет игнорировать дубликаты пакетов, но все равно будет отправлять подтверждения для них. Отправитель будет игнорировать дубликаты подтверждений.
Если пакет потерян, отправитель отправляет его повторно, как вы уже знаете.
Если подтверждение теряется, отправитель повторно отправляет исходный пакет, что приводит к повторной отправке получателем подтверждения.
Если подтверждение не получено в течение определенного времени (возможно, 60 секунд или 20 повторных попыток), то игрок считается отключенным от игры. Вы должны внедрить какое-то правило тайм-аута, иначе игрок, который отключит свой сетевой кабель, навсегда свяжет ресурсы на вашем сервере.
источник
Если вы хотите заново изобрести TCP, имеет смысл сначала взглянуть на TCP , который касается именно той проблемы, которую вы описываете (часть решения заключается в использовании пользовательских значений для попыток повторных попыток и тайм-аутов).
Решения, которые используют 2 канала, канал TCP (для надежной связи), а также канал UDP (для связи с низкой задержкой), не являются редкостью.
Некоторые решения обнаруживают, когда клиент слишком долго пропускает некоторую информацию, и запускают повторную синхронизацию, которая может использовать UDP или TCP.
Другой распространенный подход заключается в том, чтобы спроектировать коммуникацию так, чтобы она вообще не зависела от подтверждений, но это выходит за рамки вопроса.
источник
В RTS вы действительно не можете использовать протокол, такой как TCP, и не можете сделать UDP надежным. Если вы попытаетесь это сделать, игра будет зависать при каждом взлете сети.
Вместо этого вы разрабатываете протокол так, чтобы пропущенные пакеты не имели большого значения.
Короче говоря, вам все равно, где другие игроки были последним кадром, если вы знаете, где они сейчас . Длинная версия более сложная.
Тогда возникает вопрос: что вы делаете, когда пакет пропадает? И ответ ... вы думаете. Игрок, вероятно, движется по прямой линии, верно? Просто переместите их на один шаг дальше по этой линии. ... За исключением того, что ни один игрок RTS никогда не движется по прямой линии. И тогда есть обнаружение столкновения.
Это трудно. Многие игры делают это неправильно. Можно утверждать, что нет правильного ответа на это, только различные ошибки, которые можно обменять.
Причина эти игры работают очень хорошо не только то, что они думали долго и трудно об этих проблемах, но и о том, что Интернет стал довольно надежным. Практически все UDP-пакеты своевременно достигают своего пункта назначения. (Если нет постоянной проблемы, как брандмауэр)
источник