Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Приоритизация сетевых потоков

Приоритизация сетевых потоков

Поделиться
pablo80Пользовательwww11 июня 201714:12#0
Каким образом можно реализовать приоритезацию сетевого трафика TCP (и/или UDP) в Windows?
Предположим у меня 3 сокета открыты, и каждый по HTTP закачивает файл. Все три файла ровно 10МБ. Сеть ограничена в 10МБ. Скачивая эти три файла windows балансирует скчивание таким образом что обычно все три файла скачиваются одновременно. Каким образом можно сделать так чтоб один из файлов скачивался быстрее?
Я пробывал использовать qWAVE  (https://msdn.microsoft.com/en-us/library/windows/desktop/aa374117… r=-2147217396) но никакого результата.

Какие могут быть советы?

CoderInTankПостоялецwww11 июня 201715:54#1
Представь, что есть вертикальная труба диаметром 10 МБ. Сверху - интернет. Снизу - Ты. В какой то момент из интернета начинают в эту трубу сыпаться куски трех файлов, толкаясь друг с другом, мешая друг другу, заполнив всю трубу потихоньку сыпятся. И что бы ты снизу с трубой не делал, из трубы все равно высыпятся куски всех трех файлов в идеале в равном количестве аккуратно перемешанные друг с другом. Ты можешь только попросить начать сыпать определенные файлы в определенный момент. ну или паузу поставить. но это уже использование особенностей конкретного HTTP протокола. Ну или приостанавливать сами треды закачки.

Правка: 11 июня 2017 15:59

Dmitry_MilkПостоялецwww11 июня 201716:05#2
CoderInTank
> И что бы ты снизу с трубой не делал, из трубы все равно высыпятся куски всех
> трех файлов в идеале в равном количестве аккуратно перемешанные друг с другом

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

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

Правка: 11 июня 2017 16:06

Dmitry_MilkПостоялецwww11 июня 201716:21#3
Да, можно проще еще поступить, без всяких замеров времени - если использовать флаг MSG_WAITALL в recv и указывать всегда строго требуемый размер куска, скажем в 10 килобайт, после чего расписывать либо sleep(синхр) либо таймер(асинхр) с учетом нужной скорости получения.
pablo80Пользовательwww11 июня 201721:47#4
CoderInTank: пример с трубой не очень правильный. Windows tcp стак судя по всему балансирует таким образом соединения чтоб они делили канал по ровну.

Dmitry_Milk: На счет считывания с меньшей скоростью. В моем тесте есть такая вероятность что тот сокет с максимальным приоритетом ничего не отдает, в этом случае два остальных сокета должны скачивать без ограничения. Иными словами, если этот 3-й сокет X отдаёт со скоростью N кб/с то два других сокета всегда должны делить оставшийся канал (10 - N)мбпс. Я немогу знать скорость скачивания с этого сокета Х. Если бы драный windows имел нормальную имплементацию SO_PRIORITY то можно было сказать что этот сокет X имеет приоритет и сам TCP stack бы правильно отбалансировал бы. Если я начну читать с меньшей скоростью с других двух сокетов я в какой-то момент просто начну читать с сумарной скоростью меньше 10мбпс если скорость отдачи с X меньше 10.

Наверняка в играх люди уперались в эту проблему, каким образом обычно это было решено?..

pablo80Пользовательwww11 июня 201722:08#5
На счет MSG_WAITALL - проблема в том что я не знаю с какой скоростью может отдавать любой из сокетов. Канал так же может меняться, если бы я написал кучу умного кода который пытается считывать медленнее с двух других этот код каким-то образом должен пытаться читать с максимальной скоростью с сокета X и делить приблизительно поровну остаток канала на другие. Приблизительно как и приоритеты с потоками (threads) б Windows: если какие-то потоки с повышной приоритезацией будут перегружать CPU то потоки с более низким приоритетом почти будут "спать" и "делить" остатки процессора только когда другие "спят".
Dmitry_MilkПостоялецwww11 июня 201722:15#6
> Наверняка в играх люди уперались в эту проблему, каким образом обычно это было
> решено?

Какова вобще изначальная проблема-то? Эти соединения разным приложениям принадлежат или одному? Это сервер или клиент?

> Windows tcp стак судя по всему балансирует таким образом соединения чтоб они
> делили канал по ровну.
ОС вообще не может влиять на ВХОДЯЩИЙ трафик. SO_PRIORITY влияет на ИСХОДЯЩИЙ трафик, когда в системе несколько сокетов уже получили информацию для отправки наружу.

Dmitry_MilkПостоялецwww11 июня 201722:22#7
pablo80
> проблема в том что я не знаю с какой скоростью может отдавать любой из сокетов

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

pablo80Пользовательwww13 июня 201710:29#8
> Какова вобще изначальная проблема-то? Эти соединения разным приложениям принадлежат или одному? Это сервер или клиент?

Это приложение на десктопе (игра). Весь вопрос имеет отношение только к моему процессу, иными словами если пользователь злостный любитель битторентов то меня это не волнует и я не пытаюсь воевать за канала с битторент-клиентом. Инысми словами что мне ОС (Windows) отведет тем и довольствуюсь и пытаюсь приоритезировать входящий http трафик между сокетами моего процесса.

> ОС вообще не может влиять на ВХОДЯЩИЙ трафик. SO_PRIORITY влияет на ИСХОДЯЩИЙ трафик, когда в системе несколько сокетов уже получили информацию для отправки наружу.

Я думал что SO_PRIORITY выставляет приоритет сокета и ОС так же приоритизирует получение трафика, но судя по всему я заблуждался. В любом случае, windows нет поддерживает SO_PRIORITY.

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

Ну да, в принципе можно подсчитать сумарную скорость по всем открытым сокетам.

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

Клиент - это один процесс (игра), ширину канала не имеет смысла выставлять, так как она не может быть известна. К примеру, на мобильном интернете при отличной связи может быть 50Мб/с, а в час пик при такой же хорошей связи может легко упасть до 1-2Мб/с.


У меня вот такие следующие вещи происходят одновременно: получение UDP трафика, и скачивание по HTTP. UDP имеет приоритет, потом в HTTP есть приоритет скачивания одних файлов над другими.
На данный момент, я все решил упростить убрать UDP из задачи и пытаюсь разобраться и решить можно ли приоритезировать входяший трафик по HTTP. Для этого я делаю простой тест: открываю несколько TCP сокетов к серверу и скачиваю по HTTP 10МБ файл. Для теста и в настройках карты ограничил скорость до 10Мб/с. Код простой - на каждый сокет я стартую поток (thread) и в каждом потоке просто по старинке синхронно читаю из сокета. Из-за того что Windows пытается равномерно делить канал междну равноправными соединениями в результатe все мои сокеты скачивают приблизительно с одинаковой скоростью, иными словами балансировка входяших соединений в windows работает отлично.
Я не пытался, но было бы интересно сделать такой тест (хоть это и не особо имеет отношение к моей задаче): запусть два процесса и в одном открыть 3 паралельных скачки на этот 10МБ файл, а в другом процессе открыть скажем 2 сокета, и посмотреть будет ли windows делить канал по ровну на все сокеты или изначально канал поросвно делит на процессы а потом в каждом процессе поровну по сокетам.
Моя цель в моем процессе сделать возможность приоритезации каких-то сокетов над другими. В идеале конечно же я хотел бы просто "сообщить" OCe о том чтобы приоритезировала входящий трафик на определенном сокете в первую очередь. Если это не возможно хотелось бы узнать какие варианты у меня имеются и где подобное должно быть уже написано. К примеру в любом браузере наверное должен быть встроен такой функционал (чтоб отдавать приоритет скриптам и css над картинками).

Dmitry_MilkПостоялецwww13 июня 201710:38#9
pablo80
> Windows пытается равномерно делить канал междну равноправными соединениями

Откуда берется такое утверждение?

pablo80Пользовательwww13 июня 201711:58#10
> Откуда берется такое утверждение?

Судя по тестам. И при 200МБ/с и при 10мб/с у меня выходят равно распределенные скорости ка каждом сокете.

exchgПостоялецwww13 июня 201715:08#11
pablo80
> Если это не возможно хотелось бы узнать какие варианты у меня имеются и где
> подобное должно быть уже написано.
во первых есть MSG_OOB, но в твоем случае это не оно.
делай свой протокол с преоритизацией поверх ТСР.
Dmitry_MilkПостоялецwww13 июня 201719:55#12
Если сервер для всех соединений один и тот же, то можно сделать блочный протокол, когда по одному соединению будут валиться куски разных потоков данных. Приоритизацией, естественно, должен заведовать сервер, если есть данные по более приоритетным потокам - слать эти блоки в первую очередь.

Чтоб не изобретать велосипед - можно посмотреть в сторону HTTP/2.

pablo80Пользовательwww14 июня 201712:26#13
Я знаю на счет http2, именно это и идет по сокету которому я хочу дать приоритет, но есть еще другие сокеты которые я не контролирую и там я должен избежать изменений. Они должны работать так же как и работайют и если htt2 просто отключен или не работает эти другие сокеты не должы испытывать каких либо изменений
Dmitry_MilkПостоялецwww14 июня 201714:38#14
Ну другого способа, кроме уже предложенного (приостанавливать чтение из неприоритетных сокетов, если суммарное потребление упирается в "полочку"), я не вижу.

Может быть еще кто-то что-то хитрое придумает. Если б роутер и коммутаторы/модемы перед последней милей были под вашим управлением, можно было бы еще поиграться с IP precedence, но раз тут разные клиенты - этого гарантировать невозможно. Впрочем, можно еще понадеяться "на авось" и использовать для HTTP/2 сокета IP-prcedence, используемый обычно для IP-телефонии (если конечно сервер вообще позволяет выставлять precedence), но гарантии тоже не будет.

/ Форум / Программирование игр / Сеть

2001—2017 © GameDev.ru — Разработка игр