|
Общее Веб-разработка в целом, идеи, проекты... |
31.10.2016, 10:16
|
#1
|
Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Правильная организация Server<-> client
Как правильно реализовать обмен данных между сервером и клиентом при условии, что клиентов несколько (4 штуки максимум) и сервер постоянно что-то должен выполнять (т.е не должно быть блокировки)?
Само детище на C# и как я понял в тренде сейчас async/await ,но я не знаю как это использовать, a не круто делать так:
* Поток регистрации клиентов
* Поток логики
* По-потоку на каждого клиента
Еще желательно, что бы CPU-frendly это все было, так как десктопная приложенька, которая предполагается, будет работать фоном.
Тыкните в правильное направление.
|
(Offline)
|
|
31.10.2016, 12:00
|
#2
|
Бывалый
Регистрация: 26.07.2009
Сообщений: 785
Написано 362 полезных сообщений (для 995 пользователей)
|
Ответ: Правильная организация Server<-> client
Почему «не круто» делать через потоки?
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
31.10.2016, 13:13
|
#3
|
Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Ответ: Правильная организация Server<-> client
Сообщение от Andvrok
Почему «не круто» делать через потоки?
|
Процессорное время.
Какого фига все, что после обведенного красным НИКОГДА не выполняется??
Я ради эксперимента даже использовал обычный метод, и все равно, даже в дебагере дальше этого места не идет, и главное нету исключений вообще никак.
Асинхронная запись работает, а асинхронное/синхронное чтение НЕТ!
Последний раз редактировалось RegIon, 31.10.2016 в 14:19.
|
(Offline)
|
|
31.10.2016, 14:48
|
#4
|
Бывалый
Регистрация: 26.07.2009
Сообщений: 785
Написано 362 полезных сообщений (для 995 пользователей)
|
Ответ: Правильная организация Server<-> client
Я не особо по асинхронности, но сейчас сделал по примеру в мсдн и всё работает.
|
(Offline)
|
|
31.10.2016, 15:09
|
#5
|
Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Ответ: Правильная организация Server<-> client
|
(Offline)
|
|
31.10.2016, 19:11
|
#6
|
Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Ответ: Правильная организация Server<-> client
Оказалость, что если указать локальным хостом для TcpListener "127.0.0.1", то можно словить забавный баг - до него нельзя достучаться по IP локальной сети, у меня это 192.168.1.3, а если получается, то только сервер не может из него читать - только писать.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
31.10.2016, 20:44
|
#7
|
Бывалый
Регистрация: 19.06.2008
Сообщений: 679
Написано 264 полезных сообщений (для 450 пользователей)
|
Ответ: Правильная организация Server<-> client
Сообщение от Andvrok
Почему «не круто» делать через потоки?
|
Очевидно что нормальный сервер многопоточный (иначе не будут использоваться все процессоры).
Однако создавать по потоку на каждого клиента - это самый плохой способ. Большую часть времени потоки будут тупо ничего не делать а ждать данных от i/o. В итоге будут жрать память и жрать процессорное время. Короче херовая масштабируемость.
Впрочем, если там 3-4 клиента то разница вообще незначительная.
Оказалость, что если указать локальным хостом для TcpListener "127.0.0.1", то можно словить забавный баг - до него нельзя достучаться по IP локальной сети, у меня это 192.168.1.3, а если получается, то только сервер не может из него читать - только писать.
|
Много раз писал небольшие локальные серваки на дотнете, ни разу такого не наблюдал. Брандмауэр/антивирус? Версия фреймворка?
__________________
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо h1dd3n за это полезное сообщение:
|
|
31.10.2016, 23:18
|
#8
|
.
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений (для 6,863 пользователей)
|
Ответ: Правильная организация Server<-> client
Чтение с клиентов данных и их подготовка (десериализация) к употреблению в игровом цикле. Это одним потоком с использованием async/await.
Игровой цикл в своём потоке, выполняется фиксированное раз в секунду. Чем выше частота логики, тем лучше (обычно), но и CPU стоимость будет выше.
Цикл рассылки данных, может быть по той же частоте как и игровая логика, а может быть реже в два раза. Зависит от ситуации. Но должен выполнятся также конкретное раз в секунду, и сразу же после игрового цикла. Собирает данные с игрового цикла, и рассылает всем клиентам используя async/await.
Использовать поток на каждого клиента - не масштабируется, и жрёт много RAM'а, также усложняет всю логику синхронизации данных между потоками.
|
(Offline)
|
|
Эти 3 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
|
|
31.10.2016, 23:42
|
#9
|
Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Ответ: Правильная организация Server<-> client
Сообщение от h1dd3n
Много раз писал небольшие локальные серваки на дотнете, ни разу такого не наблюдал. Брандмауэр/антивирус? Версия фреймворка?
|
.net 4.6, брадмауэр спроисл разрешение - я дал.
Сменил IP на 0.0.0.0 вместо 127.0.0.1 - все работает.
Чтение с клиентов данных и их подготовка (десериализация) к употреблению в игровом цикле. Это одним потоком с использованием async/await.
|
Тут небольшая проблема.
Пусть у нас 4 клиента, шаг опроса -10 ms , сделаем до каждого асинхронный запрос на чтение данных, а придет он только через 10 + ping.
У меня сейчас Один поток логики с Thread.Sleep(10), который асинхронно обрабатывает подключение, которое асинхронно запускает цикл чтения у подключившегося клиента (кароче, поток фактически запускает). Это асинхронное чтение десериализует и вызывает делигат с получеными данными, на который подписан поток логики.
Вроде работает, только не могу с входного потока прочитать, не закрыв его .
Вернее, у меня клиент на Java. Хоть очищай, хоть не очищай выходой поток - пока его не закроешь (что нельяз, так как закроется сокет) - данные не уйдут
в c# это решилось Writer.autoFlush, а у BufferedWriter в Java такого нет и flush не помогает.
|
(Offline)
|
|
01.11.2016, 00:30
|
#10
|
.
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений (для 6,863 пользователей)
|
Ответ: Правильная организация Server<-> client
Я с Java работал лет 6 назад, и как раз работал с потоками и веб сокетами, там есть возможность опрашивать есть ли в наличии для чтения данные из сокета, и затем получать если есть, совмещаешь это с асинком и будет ок.
Гугли.
|
(Offline)
|
|
01.11.2016, 09:50
|
#11
|
Гигант индустрии
Регистрация: 13.09.2008
Сообщений: 2,893
Написано 1,185 полезных сообщений (для 3,298 пользователей)
|
Ответ: Правильная организация Server<-> client
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
01.11.2016, 10:17
|
#12
|
Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Ответ: Правильная организация Server<-> client
Сообщение от Nex
|
4 подобных ролика посмотрел и в вкурил как это работает. Так же как в JS, только вызывается не калбек - а продолжается как Corotutine в Unity.
|
(Offline)
|
|
01.11.2016, 12:01
|
#13
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Ответ: Правильная организация Server<-> client
Топикстартер, ты что - переделал первый пост? Когда я читал его первый раз, там была фраза, что мол, потоки плохо без особой мотивации - что и вызвало недоумение.
Вообще - солидарен с mok-иной архитектурой. Вроде ещё механизм "пул потоков" по теме может пригодиться, но я с ним не работал.
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
01.11.2016, 12:10
|
#14
|
Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Ответ: Правильная организация Server<-> client
Сообщение от impersonalis
Топикстартер, ты что - переделал первый пост? Когда я читал его первый раз, там была фраза, что мол, потоки плохо без особой мотивации - что и вызвало недоумение.
Вообще - солидарен с mok-иной архитектурой. Вроде ещё механизм "пул потоков" по теме может пригодиться, но я с ним не работал.
|
Нет, не переделал . async/await - не потоки как таковые.
|
(Offline)
|
|
01.11.2016, 20:21
|
#15
|
Бывалый
Регистрация: 19.06.2008
Сообщений: 679
Написано 264 полезных сообщений (для 450 пользователей)
|
Ответ: Правильная организация Server<-> client
Судя по всему в этой теме смешалось в кучу все: кони, люди, потоки, таски, async/await, threadpool...
- Создавать потоки вручную (использовать класс Thread) в современном C#/.NET нужно только в 0.00001% случаях, и ситуация ТС под этот случай не подходит.
- В C# нынче (и вообще-то уже довольно давно) оперируют тасками - Task, Task<T>. Таск это просто задача, сами по себе таски никакого отношения к потокам не имеют. Таски вообще совершенно отдельная от async/await фича.
- Для того чтобы сервер нормально масштабировался хорошо бы чтобы потоки не блокировались и переиспользовались. Async/await к этому отношения не имеет. Асинхронные серверы были в дотнете ЕМНИП со 2.0 версии фреймворка - IAsyncResult паттерн.
- Когда мы создаем таск (Task), то скорее всего (такое поведение по умолчанию), мы ставим эту задачу на выполнение шедулеру (TaskScheduler).
- Шедулер по своему внутреннему алгоритму как-то выполняет задачи. Дефолтный шедулер использует ThreadPool. В дотнете есть и другие шедулеры. Можно также написать свой шедулер. Но это не понадобится (скорее всего).
- Async/await - это просто синтаксический сахар C# (на уровне clr об async/await даже не нужно ничего знать). Самое главное понять что он никакой магии не делает.
- Использовать Thread.Sleep(10) - гиблое дело. Надо использовать await Task.Delay(10). То есть пока мы ждем эти 10мс, поток может пойти и выполнить какую-нибудь работу.
- При использовании TPL (таски, шедулер и Ко) совсем не обязательно что продолжение будет выполняться тем же потоком. То есть: есть 2 задачи - прочитать из 1 сокета, и обработать, и прочитать из 2 сокета и обработать. Предположим действие происходит следующим образом: поток A обрабатывает первую задачу, он доходит до чтения и дальше ничего делать не может пока данные не придут. Конечно он идет делать другую полезную задачу - обрабатывать задачу 2. Но пока он это делал в 1 задаче из i/o пришли данные и надо бы выполнение то продолжить, но т.к. поток А занят, этим займется поток Б (который возьмется из тредпула).
- Пункт выше объясняет почему создавать потоки вручную - идиотизм. Может получиться так что: создали поток, внутри потока, где-то есть await. Значит все продолжение после await может быть выполнено потоком из тредпула. Получается что созданный вручную поток потерян навсегда и вообще не будет использоваться.
Тебе надо - создать таск который в бесконечном цикле принимает соединения. Когда принимаешь соединение создаешь таск с бесконечным циклом в котором принимаешь данные.
Далее есть 2 варианта - если у тебя архитектура запрос/ответ (ну как http примерно) то сразу же начинаешь обрабатывать. Если у тебя что-то типа реалтайм сервера, то ты полученные данные просто куда-то кладешь (в какое-то потокобезопасное хранилище). Нету никакого "шага" в виде 10мс на чтение. Читаешь сколько можешь.
Вот на обработку (если мы говорим о реалтайм сервере) уже может быть шаг предположим 8мс. Каждый раз в этом реалтайм цикле (а это тоже таск, не поток), ты берешь все данные из этого "потокобезопасного хранилища" и обрабатываешь их, потом снова уходишь в Task.Delay.
__________________
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 02:38.
|