2016-01-02 2 views
1

В настоящее время я нахожусь в личном проекте для обучения. Я хочу подключиться к UDP для приложений, таких как игры. Каждая отправленная датаграмма имеет определенный заголовок, который указывает, к какому «логическому» каналу он принадлежит, например, канал 0 подобен UDP с дополнительными служебными данными заголовка, а в канале 1 используется большее количество заголовков для обеспечения некоторой дополнительной надежности. Целью каналов является «автоматическое» разделение сообщений на логические группы, вплоть до определенной суммы.. Net Socket (UDP) Отправка, получение и планирование

В моем текущем коде, есть простой цикл в отдельном потоке, который обрабатывает отправки и получения:

// This is pseudo code 
public void Tick() { 
    if(Socket.Poll) { 
     do { 
      ReadMessage(); 
     } while(Socket.Available > 0) 
    } 

    SendQueuedOutgoingMessages(); 
} 

Хотя это работает на идеальном мире, у меня есть ощущение, что эта логика терпит неудачу, когда есть слишком много входящих или исходящих сообщений. Можно ли использовать один и тот же сокет для одновременной отправки и получения сообщений (например, передача и получение являются асинхронными или в разных потоках)? Даже если это возможно, было бы лучше, если бы я просто использовал два или более UDP-сокета (или смешивал сокеты TCP и UDP, если мне нужна надежность), имея в виду особую поддержку?

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

Редактировать: добавив дополнительную информацию о коде.

Метод Tick() определяется как определенное количество раз в секунду, если он немедленно возвращается. Например, 30 раз в секунду, если нет новых сообщений о входе или выходе, и меньше, если требуется некоторое время для отправки или получения данных. Я использовал блокировку методов ReceiveFrom и SendTo, чтобы избежать ожидание ожидания или вызовов, таких как Sleep (0).

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

ответ

0

Независимо от того, зависит или нет использование двух сокетов для приема и отправки отдельно или только одного. Если вы собираетесь отправлять много сообщений, и даже если вы находитесь в выделенном потоке, сокет может блокироваться, если исходящая очередь, которая используется сокетом, будет заполнена.

Существует несколько решений этой проблемы. Использование двух сокетов и 2 отдельных потоков - один из них, другой выбор в сочетании с асинхронными сокетами. Дело в том, что вы не хотите прекращать прием только потому, что отправка может блокироваться.

Каждое из этих возможных решений имеет свою собственную сложность.

Выбрать api предназначено для проверки того, что для определенного сокета есть что-то получать, но вы также можете использовать его для определения того, станет ли сокет снова доступным для записи.Вам нужна опция сокета, чтобы поставить сокет в состояние без блокировки, и вам нужно проверить коды возврата E_WOULDBLOCK с каждой отправкой. Если это так, вышли из строя, и вы должны сами отправить сообщение в очередь.

Вы действительно не отправляете и не получаете в одно и то же время, это последовательно. Вы используете select, чтобы проверить, доступен ли сокет для записи и чтения, используя 2 битмакса, управляемых с помощью fd_set api. Вы можете использовать select даже в нескольких сокетах одновременно. Затем, если выбор, который является блокирующим вызовом, возвращает, вы можете проверить каждый отдельный бит, чтобы проверить, какие действия необходимо выполнить.

Причина, по которой отправка может блокироваться, если сокет не помещен в неблокирующее состояние, заключается в том, что выходная очередь сокета может быть заполнена. Если сокет блокируется, он просто ждет, пока очередь снова станет готовой. Но во время этого ожидания вы не можете получить что-либо в этом же сокете. Именно по этой причине вам нужны неблокирующие сокеты и select api в сочетании с каким-то механизмом массового обслуживания.

+0

Под «select» вы подразумеваете обнаружение всякий раз, когда есть что-то отправить/получить, а затем выполнить соответствующую асинхронную операцию как можно скорее? В этом случае правильно ли предположить, что Socket может асинхронно выполнять операцию «Отправить и получение» одновременно? – Kirlim

+0

не в то же время, но вы проверяете, действительно ли можно отправить что-то перед отправкой, и вы также проверяете, есть ли что-нибудь, что можно получить. Таким образом, вы никогда не блокируете. Предположим, что вы выполняете отправку, и очередь заполнена, вы должны заблокировать отправку, и пока очередь будет заполнена, вы не получите ее, даже если она может быть получена. Сетевое программирование - это действительно передовая тема, и код легко усложняется. –

+0

Я принял этот ответ. Было бы неплохо, если бы вы могли добавить свой комментарий к ответу, поскольку это связано с вопросом. – Kirlim

0

Почему не просто стандартная настройка цикла чтения?

while (true) 
    ReadMessage(); 

Нет необходимости в планировании или дросселировании. Нет необходимости знать, готов ли пакет или нет.

Вы можете читать и писать одновременно в одном гнезде UDP.

Нет необходимости в исходящей очереди. Просто отправь.

+0

Что вы имеете в виду, это использовать два разных потока, один только для отправки и другой только для получения? – Kirlim

+0

Это был бы хороший способ сделать это. Вы также можете использовать async IO, но я не вижу никаких доказательств того, что вам нужно. Также обратите внимание, что выбор и опрос - это устаревшие модели программирования, по крайней мере, в мире .NET. – usr

+0

Не знал этого (и кажется, что Poll подает GC). На самом деле, это довольно интересно. – Kirlim