Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Общие вопросы по .NET и C# > Пул потоков... |
Автор: STRELOKBMSTU 11.1.2010, 12:06 |
Нужно создать что-то типа пула потоков внутри Win-сервиса. Пользователи будут подключаться к серверу, регистрироваться на нем, будет создаваться отдельный поток, а в нем сокет для дальнейшего обмена информацией... Соответственно на сервере должен быть список пользователей с ключами и информацией о пользователе, к примеру Dictionary<GUID,UserObject>... в случае необходимости отпраки сообщения по ключу, сервис обращается к нужному потоку и отправляет сообщения на нужный сокет... В общем так мне видится реализация того чего хочу, но не разу не писал подобного, как реализовать подобное хранение потоков и обращение к ним??? |
Автор: mrbrooks 11.1.2010, 12:10 |
STRELOKBMSTU, посмотри в сторону класса ThreadPool камрад. Добавлено через 1 минуту и 1 секунду http://msdn.microsoft.com/ru-ru/library/system.threading.threadpool.aspx |
Автор: STRELOKBMSTU 11.1.2010, 12:27 |
Посмотрел ThreadPool, возможно он и подойдет, если увеличить максимальное число потоков, но мой вопрос скорее по организации регистрации и разрегистрации пользователей, т.е. как по ключу определить в каком именно потоке висит мой пользователь? и как в случае необходимости разрегистрировать пользователя на сервере опять же по ключу? |
Автор: STRELOKBMSTU 11.1.2010, 13:16 |
Разобрался с пулом, мне нужен не пул а обычный запуск каждого сокета в отдельном потоке, но как это все должно храниться, пока не ясно... |
Автор: STRELOKBMSTU 11.1.2010, 13:36 |
Можно ли создать как-нибудь список потоков? |
Автор: mrbrooks 11.1.2010, 13:53 |
в смысле - аля массив потоков? если необходимо - то конечно можно. используй те же коллекции. Добавлено через 4 минуты и 27 секунд но честно говоря теряюсь в догадках чем не подходит тот же ThreadPool.QueueUserWorkItem. |
Автор: STRELOKBMSTU 11.1.2010, 14:02 | ||
Да я все никак не могу разобраться на каком этапе создавать новый поток, у меня слушается порт, соответственно сокет создается внутри самого сервиса а не в новом потоке... а чтобы он создавался в новом потоке, надо и слушать порт в отдельном потоке. Как организовать несколько висящих в памяти сокетов с регистрацией и разрегистрацией их? Вот немного текущего кода:
|
Автор: PashaPash 11.1.2010, 14:45 |
STRELOKBMSTU, посмотри msdn по TcpListener.BeginAcceptSocket |
Автор: STRELOKBMSTU 11.1.2010, 15:13 |
PashaPash, пасиб, интересная вещь, сейчас ознакомлюсь... |
Автор: STRELOKBMSTU 11.1.2010, 15:35 |
все равно какая-то мутная картина в голове... ведь этот метод выполняется в том же потоке, в котором и был бызван, т.е. многопоточность не получается... |
Автор: mrbrooks 11.1.2010, 16:21 |
да это обыкновенная асинхронная операция ожидающая входящее подключение. вообще кстати тов. Joseph Albahari советует использовать асинхронные методы в крайних случаях - заменив их использованием асинхронными делегатами. но это к слову. я так понимаю работа идет с сервером. вообще классическая модель для сервера это использовать потоки + семафоры. |
Автор: tol05 11.1.2010, 17:18 | ||||
Так называемая асинхронная модель программирования (Asynchronous Programming Model) В двух словах - есть рабочие потоки (Thread-ы, как мы привыкли их понимать) и потоки ввода-вывода (они еще называются потоками завершения) В стримах когда мы используем методы BeginХХХХ - мы активно используем потоки ввода\вывода, перекладывая тем самым часть нагрузки с процессора на драйвер устройства Об этом хорошо написал Рихтер в своей книге "CLR via C#". В главе о асинхронных операциях. Приведу две цитаты
О FileStream
Я могу ошибаться, но по-моему TcpListener.BeginAcceptSocket использует потоки ввода-вывода. Но даже если это не так.. то все равно, я бы любом случае использовал бы именно TcpListener.BeginAcceptSocket, а не создавал бы собственный (рабочий) поток. |
Автор: STRELOKBMSTU 11.1.2010, 17:50 | ||||
Т.е. если одновременно придет много запросов от клиентов, они все встанут в очередь на CallBack или будут выполняться параллельно? Да, и на BeginAcceptSocket цикл не зависает и не ждет события прихода сокета, а выполняется бесконечно, процесс конечно не сильно нагружается, но что-то не нравится этот бесконечный цикл:
|
Автор: PashaPash 11.1.2010, 19:14 | ||||
Параллельно, на потоках из пула.
Используй семафор для ограничения на количество одновременно висящих BeginAcceptSocket. Или используй синхронный AcceptSocket, но вынеси обработку в отдельный поток. У того же Joseph Albahari есть пример: http://www.albahari.com/nutshell/ch20.aspx |
Автор: mrbrooks 12.1.2010, 09:22 | ||
Он как бэ советует вызвать синхронную версию метода через асинхронный делегат. Однако рьяно не настаивает. |
Автор: STRELOKBMSTU 13.1.2010, 13:55 | ||||||||||
по BeginAcceptSocket у нас одновременно запускается несколько слушалок, ошидающих подключения сокета, так? Тогда почему не работает WaitOne здесь:
Ведь WaitOne по идее должен заблокировать текущий цикл до тех пор пока в DoAcceptSocketCallback не будет вызван clientConnected.Set(), разве не так??? И в семафоре если делаю так:
цикл бегает бесконечно, т.е. слушалки постоянно создаются? как в этом случае отрабатывает строчка
|
Автор: STRELOKBMSTU 13.1.2010, 15:15 | ||||
По этой строчке у нас создается отдельный поток, который встает в ожидаение сокета??? Или происходит что-то другое? Прост в семафоре у нас ничего не висит, его счетчик пуст, что логично, ведь делегат DoAcceptSocketCallback запускается четко в момент когда приходит запрос от клиента, т.е. возникает какое-то событие??? Оно возникает в основном потоке? и что интересно, то что цикл
бегает бесконечно, т.е. семафор заполнится лишь при наличии нескольких параллельно работающих колбэков... как убрать этот бесконечный цикл? |
Автор: PashaPash 13.1.2010, 17:00 |
clientConnected - это ManualReset или AutoReset Event? А семафор надо немного по другому юзать - ждать перед BeginAcceptSocket, освобождать в начале DoAcceptSocketCallback. |
Автор: WolfTheGrey 23.1.2010, 05:21 |
А зачем вы вызываете Thread.Sleep() Он не усыпляет поток, а откладывает его в очередь потоков на определенное время. И то не факт, что поток возобновит свою работу именно через этот промежуток времени. Отведь себе на вопрос: сколько клиентов ты собераешся одновременно обробатывать? и нужен ли тебе весь этот Многпоточный хлам? И вернемся к теме: сервер: имеет структуру с данными о клиенте. Копии структур (клиентов) хранятся в масве. Хранить в структуе можно все, даже его IP адрес. при подключении клиента TcpClient client=listener.AseptTcpClient(); ты уже знаешь его IP и ищеш в базе его данные по его IP. Можешь дождаться когда клиент пришлет свой пароль : string pass=client.Read(); И вернемся к многопоточности: Методы- Read(); и AseptTcpClient() - создают новый поток. (так мне компилятор сказал - когда я расматривал создаваемые потоки в процессе работы програмы) |
Автор: PashaPash 23.1.2010, 13:07 | ||||||||
А зачем ты написал этот кусок текста? Thread.Sleep там закомменчен.
Многопоточный хлам нужен если нужна обрабатывать больше одного клиента одновременно. Думаю, если бы клиент был ровно один, то и топик бы не появился. Разработчики - ленивые существа ![]()
В теме не упоминалось что вообще есть какая-то база данных. Перечитай первое сообщение - там подразумевалось хранить инфу о подключенных в данный момент пользователях. Странно при подключении искать там "его IP". Про пароль тоже неожиданно ![]()
Компилятор, в процессе работы? хм... а у меня отладчик говорит что AcceptTcpClient не создает поток. И что какой-то выбранный наугад StreamReader.Read - тоже не создает. Мой отладчик сильнее твоего компилятора! ![]() |
Автор: WolfTheGrey 24.1.2010, 03:02 | ||||||||
![]() |
Автор: PashaPash 24.1.2010, 04:56 | ||
Ок, может быть не дошло, объясню по другому - в этом топике нет ни одного вызова Thread.Sleep. Рихтер наверняка писал и про другие функции, не имеющие отношения к этому топику, не стоит копипастить сюда всю книгу.
Ок, еще раз: 1. В списке держим подключенных пользователей 2. При отключении - удаляем 3. При подключении - ищем в списке по IP 4. И гарантировано не находим... |
Автор: uranpro 24.1.2010, 13:59 | ||
можно мне плюсик за пост =) мой сервер, до 4к подключений
используй BinaryFormatter !!! гораздо быстрее и меньше весит. |
Автор: PashaPash 24.1.2010, 16:49 |
uranpro, мелкий баг - чисто теоретически, после 10 ошибок между try и BeginAccept в AcceptCallBack сервер перестанет аццептить вообще ;) |
Автор: uranpro 24.1.2010, 16:56 | ||
PashaPash, ага, спасибо, исправим =) Добавлено через 3 минуты и 43 секунды
|
Автор: WolfTheGrey 25.1.2010, 14:29 |
uranpro, Понравился код, и от меня ему плюсик поставьте! Только я одного не понял, в каком месте происходит массовая рассылка? (тоесть один сказал - все услышали). Если это не предусмотренно, то нужно как то истправлять положение! ![]() |
Автор: uranpro 25.1.2010, 16:09 | ||
WolfTheGrey, а это уже другой класс =) у меня. вставь в делегат GetData Connections и все, делов минута =) тело делегата
|
Автор: WolfTheGrey 26.1.2010, 05:48 |
uranpro, я так умею, а вот на асинхронных операциях бы! |
Автор: uranpro 26.1.2010, 13:14 | ||
вот, без разницы, асинхронная модель или нет
|
Автор: WolfTheGrey 27.1.2010, 01:21 |
А как проверить сколько клиентов вытянит сервер? (учитывая что комп один ) |