Получение данных с помощью Winsock

Прямо сейчас я программирую сеть для своей онлайн-игры, и я не совсем уверен, что делать с получением данных. Проблема в том, что я не могу угадать размер пакета, поэтому я подумал о том, чтобы прочитать всего 4 байта из пакета и преобразовать их в int, чтобы узнать размер пакета. Затем я просто создам буфер такого размера и получу остальную часть пакета, это хорошая идея?

К вашему сведению, я использую неблокирующий ввод-вывод.


person Community    schedule 23.03.2010    source источник
comment
Вы используете TCP или UDP? UDP позволит вам получать сообщения на границах сообщений, но TCP позволит вам только передавать данные. Однако вы можете быть уверены, что ваши пакеты будут меньше 1500 байт, так как это максимально допустимый размер в обычном Ethernet.   -  person bramp    schedule 24.03.2010
comment
Даже если вы уверены, что ваши пакеты меньше этого размера, как вы узнаете, когда заканчивается одно сообщение и начинается другое? Вам нужно добавить информацию в свой протокол (например, размер сообщения), чтобы быть уверенным.   -  person Justin Ethier    schedule 24.03.2010


Ответы (3)


Ваш подход звучит разумно - вы, по сути, встраиваете размер сообщения в заголовок сообщения, что, вероятно, является наиболее надежным способом справиться с ним в вашей ситуации. В качестве альтернативы вы можете либо использовать пакеты фиксированной длины (ick), либо использовать какой-либо символ-разделитель (который НЕ будет работать для двоичных сообщений).

Эта ссылка socket-protocol-fundamentals содержит некоторую дополнительную информацию, которая может помочь.

person Justin Ethier    schedule 23.03.2010
comment
Эти два метода (префикс размера и конечный разделитель) являются стандартными способами решения этой проблемы. - person caf; 24.03.2010

Если вы используете сокеты TCP, НИКОГДА не полагайтесь на размер пакета. Поток данных представляет собой поток байтов, а не поток пакетов.

person Giuseppe Guerrini    schedule 23.03.2010
comment
Я использую сокеты TCP, что вы имеете в виду? (извините за глупость) - person ; 24.03.2010
comment
Правильно, вы должны полагаться на размер сообщения, указанный в вашем заголовке. Размер пакета не имеет значения, за исключением того, что он может быть меньше вашего сообщения (другими словами, сообщение может быть получено несколькими пакетами). - person Justin Ethier; 24.03.2010
comment
Извините, я совершенно неправильно понял ваш вопрос. И я быстро удалю свой совершенно не по теме ответ. Вы говорили не о размере сетевого пакета, а о размере пакета приложения. Проблема с TCP заключается в том, что сеть может разделить ваш логический пакет на фрагменты, поэтому получатель должен снова их перекомпоновать. до свидания - person Giuseppe Guerrini; 24.03.2010
comment
А, я вижу, нет проблем. Большое спасибо, Джастин. - person ; 24.03.2010
comment
(слишком много комментариев - слишком поздно, чтобы удалить мой ответ! - позор мне!) - person Giuseppe Guerrini; 24.03.2010

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

Вы не указали TCP или UDP, поэтому я просто дам вам общие рекомендации.

Для TCP или UDP просто выделите один буфер размером N, где N — это максимальный размер сообщения, которое вы могли бы отправить с удаленного игрока или сервера. Для UDP я бы рекомендовал не превышать 1500 байт. Для TCP у вас могут быть большие размеры.

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

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

Для TCP вы, по сути, формируете свои сообщения так, как вы описываете. Каждое сообщение имеет заголовок, определяющий количество байтов, которые должны следовать. Но сделайте то же самое, что и я для UDP, — добавьте собственный заголовок для проверки целостности. Закройте сокет, если вы когда-либо получите повреждение сообщения и ASSERT.

В TCP из-за сегментации TCP вы можете не получить все сообщение в одном и том же вызове "recv". То есть, если вы получили только частичное сообщение, сохраните его во временном буфере. При последующем вызове recv (в следующем игровом кадре) добавьте в этот буфер. Вам придется хранить переменные для отслеживания ожидаемого конца сообщения, чтобы случайно не прочитать следующее сообщение, которое могло быть отправлено.

Удачи.

person selbie    schedule 23.03.2010