23 / 23 / 5
Регистрация: 05.12.2013
Сообщений: 215
1

Сетевая игра в режиме реального времени. Qt

25.10.2014, 19:44. Показов 3166. Ответов 15
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет!
Решил в учебных целях сделать на Qt сетевую игру (для локальной сети) в режиме реального времени. Всё что я знаю о работе с сетью в Qt - глава из книги Макса Шлее. Ну и конечно, в силу своей нубости столкнулся с рядом проблем. А точнее проблема только одна - на "хосте" игра летает, на "клиентах" - лагает. Причин, наверное множество, и вот какие вопросы я хотел бы задать:

1. До того, как я увидел тормоза на "клиенте" я считал, что выделить на клиента 1 порт - это хорошая идея. Сейчас я начинаю задумываться о том, что через 1 порт, наверное, информация идёт туговато. А может я ошибаюсь. Сколько примерно выделяют портов для игр?

2. Таймер запущен только на хосте, для всех клиентов update() происходит по сигналу readyRead() от сервера, после соответствующего чтения информации. Опять же не знаю, хорошая это идея или плохая. Как обычно поступают для координации времени в играх?

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

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

5. Поскольку учился я по книге М. Шлее, умею подключаться только к конкретному порту конкретного компьютера (по его имени). А как же сделать что-то типа "мониторинга" сети? Вот как, извиняюсь, в варкрафте: Кто-то создал игру - другие видят, что появился такой-то хост, и могут к нему законнектиться. Как происходит сей процесс?

Буду благодарен любым советам! Возможно данные вопросы интересны не только мне, и данная тема разовьётся в хорошую дискуссию. Пожалуйста, активно принимаем участие)
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.10.2014, 19:44
Ответы с готовыми решениями:

Работа в режиме реального времени
Возможно создать не там, ибо вопрос практически не касается тему Qt, но разработка именно в нем....

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

Парсер логов в режиме реального времени
Доброго времени суток всем. нужны светлые идеи :) Возникла мысль замутить парсер логов в режиме...

Отображение данных в режиме реального времени
Есть такая небольшая программка, которая симулирует наклономер по двум осям. Просто отобразить...

15
187 / 172 / 38
Регистрация: 03.08.2012
Сообщений: 596
25.10.2014, 22:05 2
Цитата Сообщение от Nelkor Посмотреть сообщение
2. Таймер запущен только на хосте, для всех клиентов update() происходит по сигналу readyRead() от сервера, после соответствующего чтения информации. Опять же не знаю, хорошая это идея или плохая. Как обычно поступают для координации времени в играх?
Может быть это и есть основная причина лагов у клиента?
Хотя все зависит от игры, но я считаю, что update стоит делать независимо от того, пришли данные от сервера или нет
0
1443 / 1326 / 131
Регистрация: 20.03.2009
Сообщений: 4,689
Записей в блоге: 11
25.10.2014, 23:35 3
Nelkor, без профилирования все перечисленное полная ерунда. Профилирование
0
Почетный модератор
11525 / 4320 / 448
Регистрация: 12.06.2008
Сообщений: 12,410
26.10.2014, 01:25 4
Лучший ответ Сообщение было отмечено Nelkor как решение

Решение

Цитата Сообщение от Nelkor Посмотреть сообщение
1. До того, как я увидел тормоза на "клиенте" я считал, что выделить на клиента 1 порт - это хорошая идея. Сейчас я начинаю задумываться о том, что через 1 порт, наверное, информация идёт туговато. А может я ошибаюсь. Сколько примерно выделяют портов для игр?
Эти порты виртуальные и на скорость не влияют. Если для каждого клиента открывать отдельный порт, то прироста производительности не будет. Да и количество клиентов тогда будет ограничено количеством портов.

Цитата Сообщение от Nelkor Посмотреть сообщение
4. TCP-соединение.
В TCP надо учитывать то, что это поток данных. Т.е. если отправляются два мелких пакета, то придти они могут в виде одного большого или 10 ещё более мелких. Так же было замечено, что Qt реально отправляет данные только когда начинает выполнять свой основной цикл (при выходе из функций или по qApp->processEvents). Если это не используется, тогда надо проталкивать данные через QTcpSocket::flush(). Возможно, это и приводит к лагам.

Цитата Сообщение от Nelkor Посмотреть сообщение
Кто-то создал игру - другие видят, что появился такой-то хост, и могут к нему законнектиться. Как происходит сей процесс?
Я вижу три способа:
- использовать общий сервер, который подсказывает, кто создал игру и как к нему подключиться
- время от времени сканировать подсеть
- время от времени отправлять широковещательный UDP запрос
1
Заблокирован
26.10.2014, 05:01 5
немного не по теме.
на сервер мощный такой тебе денег не хватит
0
Почетный модератор
11525 / 4320 / 448
Регистрация: 12.06.2008
Сообщений: 12,410
26.10.2014, 13:11 6
Цитата Сообщение от poss Посмотреть сообщение
на сервер мощный такой тебе денег не хватит
"такой" - это какой? Автор ничего не написал о требованиях к производительности или скорости сети.
0
23 / 23 / 5
Регистрация: 05.12.2013
Сообщений: 215
26.10.2014, 14:51  [ТС] 7
Цитата Сообщение от poss Посмотреть сообщение
на сервер мощный такой тебе денег не хватит
Бухгалтер, милый мой бухгалтеееер...

Добавлено через 1 минуту
Большое спасибо, Humanoid. Вы не против, если я буду обращаться к Вам впредь по проблемным вопросам, связанным с сетями?)
0
Заблокирован
26.10.2014, 14:52 8
слышь, ТЫ? тебе нормальный совет дали.
Под 1000 активными клиентами, твоя VPS за 50$ обвалится.
0
23 / 23 / 5
Регистрация: 05.12.2013
Сообщений: 215
26.10.2014, 14:55  [ТС] 9
И кстати, я правильно понимаю, что широковещательный UDP-запрос, это writeDatagram(..., QHostAdress::Any, ...) ?

Добавлено через 1 минуту
Цитата Сообщение от poss Посмотреть сообщение
слышь, ТЫ? тебе нормальный совет дали.
Под 1000 активными клиентами, твоя VPS за 50$ обвалится.
Да спасибо, я уже понял, что ты лучше всех знаешь, на что у меня хватит денег, а на что нет. И поосторожнее с оффтопами, а то забанят еще(
0
Почетный модератор
11525 / 4320 / 448
Регистрация: 12.06.2008
Сообщений: 12,410
26.10.2014, 21:31 10
Цитата Сообщение от Nelkor Посмотреть сообщение
И кстати, я правильно понимаю, что широковещательный UDP-запрос, это writeDatagram(..., QHostAdress::Any, ...) ?
Скорее QHostAdress::Broadcast - это аналог адреса 255.255.255.255
QHostAdress::Any используется для открытия порта на всех интерфейсах, что является аналогом адреса 0.0.0.0 и это не сработает как широковещательный запрос.

Можно даже просто на 255.255.255.255 послать сообщение. Но надо учитывать, что широковещательные пакеты только внутри подсети работают... ближайший роутер их вряд ли выпустит во внешнюю сеть. Т.е. если у вас адрес 192.168.20.5, а маска подсети 255.255.255.0, то этот пакет будет доступен только для адресов 192.168.20.*

Цитата Сообщение от Nelkor Посмотреть сообщение
Вы не против, если я буду обращаться к Вам впредь по проблемным вопросам, связанным с сетями?)
На форуме принято, что вопросы задаются в соответствующей теме. Так больше шансов получить ответ, т.к. если один не знает ответ, то другие подскажут. К тому же, готовый ответ на вопрос в свободном доступе часто оказывается полезным для других людей, с похожими вопросами.

Цитата Сообщение от poss Посмотреть сообщение
Под 1000 активными клиентами, твоя VPS за 50$ обвалится.
Может, у автора всего 10 активных клиентов, каждый из которых тянет 1 КБ/с по сети и все в сумме грузят процессор на 1% и жрут 10 МБ памяти... и при этом используется навороченный выделенный многопроцессорный Xeon с 256 гигами памяти и 10-гигабитным каналом в интернет.
Откуда такие предположения о 1000 активных клиентах и цене VPS'а, если автор об этом ничего не говорил?
0
23 / 23 / 5
Регистрация: 05.12.2013
Сообщений: 215
27.10.2014, 21:38  [ТС] 11
Humanoid, спасибо за советы! Кстати, при получении от сокета сигнала disconnected() реально выцепить его бывший дескриптор? После отсоединения-то он уже равен -1 и не очень то понятно, какой именно клиент отключился. Лично я вижу такое решение - вести QList<qintptr>, в котором хранить все дескрипторы, а при поступления сигнала о дисконекте пробегаться по этому списку и всех проверять (А как проверять? isOpen()? isValid()?) Ну и кто не отзовётся на проверку, того и считать отсоединившимся... Это правильное решение или уже изобретено более круглое колесо?
0
Почетный модератор
11525 / 4320 / 448
Регистрация: 12.06.2008
Сообщений: 12,410
27.10.2014, 22:06 12
Можно так:
C++ (Qt)
1
QTcpSocket *sock = (QTcpSocket*)this->sender();
теперь sock - это и есть указатель на тот сокет. Только желательно его вначале проверить на NULL.
0
23 / 23 / 5
Регистрация: 05.12.2013
Сообщений: 215
27.10.2014, 22:14  [ТС] 13
Цитата Сообщение от Humanoid Посмотреть сообщение
Можно так:
C++ (Qt)
1
QTcpSocket *sock = (QTcpSocket*)this->sender();
теперь sock - это и есть указатель на тот сокет. Только желательно его вначале проверить на NULL.
В таком случае его дескриптор будет равен -1 Потому что сендером он является уже после дисконнекта
0
1443 / 1326 / 131
Регистрация: 20.03.2009
Сообщений: 4,689
Записей в блоге: 11
27.10.2014, 22:20 14
Nelkor, так заведи карту QMap<QTcpSocket*, Client*>.
0
23 / 23 / 5
Регистрация: 05.12.2013
Сообщений: 215
28.10.2014, 22:01  [ТС] 15
Цитата Сообщение от Dmitriy_M Посмотреть сообщение
Nelkor, так заведи карту QMap<QTcpSocket*, Client*>.
Я не понимаю, что за тип данных Client*

Добавлено через 3 минуты
humanoid, нужна помощь! Я пытаюсь инициализировать сокет таким методом:

QTcpSocket *psocket = new QTcpSocket(this);
psocket->setSocketDescriptor(descr);

descr - это сохранённый дескриптор подключенного сокета. Но сообщение, отправленное как psocket->write(...) не доходит, а в QDebug выводится QSocketNotifier: Multiple socket notifiers for same socket 476 and type Read

Как отправлять сообщение какому-то конкретному клиенту?

Добавлено через 2 минуты
Может быть, вместео дескрипторов вести учет указателей на сокеты присоединившихся клиентов?
0
Почетный модератор
11525 / 4320 / 448
Регистрация: 12.06.2008
Сообщений: 12,410
28.10.2014, 22:41 16
Цитата Сообщение от Nelkor Посмотреть сообщение
Может быть, вместео дескрипторов вести учет указателей на сокеты присоединившихся клиентов?
Я всегда так и делал... получал указатель через QTcpServer::nextPendingConnection()
0
28.10.2014, 22:41
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.10.2014, 22:41
Помогаю со студенческими работами здесь

Не обрабатывается скрипт в режиме реального времени
Привет! У меня есть страничка http://hobbylife-market.ru/kabinet/korzina - если добавить туда...

ОС для работы в режиме реального времени?
Подходит ли windows server 2003 для работы в режиме реального времени, если нет, то с какими...

Выполнение jquery в режиме реального времени
Есть скрипт который определяет ширину и и сходя из этого подгоняет мин и макс. кол-во элементов в...

Обработка звука в режиме реального времени
Вопрос очень общий. Позволяет ли это делать C#? Каковы методы обработки? Прошу советы, ссылки,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru