crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V   1 2 3 >  
Ответить в данную темуНачать новую тему
> QThread, QEvent, QTcpServer, взаимодействия между потоками
512es
  опции профиля:
сообщение 10.11.2008, 16:00
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

Спасибо сказали: 5 раз(а)




Репутация:   0  


всем привет!

пишу многопоточный высокопроизводительный сервер на qt.

сервер прослушивает коннекты на определённый порт и на каждое входящее соединение создаёт отдельный поток.
при каждом пришедшем пакете поток отсылает главному потоку сообщение через customEvent.

вроде работает, только не знаю как правильнее заставить все дочерние потоки (или один выборочно) отослать определённый пакет клиентам?


закинул все потоки массив QVector и передаю в customEvent главного потока ид того кто отправил. правильный путь ли я выбрал?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 10.11.2008, 16:27
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9642
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(512es @ 10.11.2008, 19:00) *
при каждом пришедшем пакете поток отсылает главному потоку сообщение через customEvent.
может лучше сигналы и слоты использовать, Qt'я их сама в события превратит.

Цитата(512es @ 10.11.2008, 19:00) *
вроде работает, только не знаю как правильнее заставить все дочерние потоки (или один выборочно) отослать определённый пакет клиентам?
а вчем именно загвоздка?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 10.11.2008, 16:48
Сообщение #3


Мастер
******

Группа: Модератор
Сообщений: 3283
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Если я тебя правильно понял, то тебе нужен менеджер соединений. А раз так, то обычным QVector тебе не обойтись, нужно создать класс для управления и просмотра соединений (сокетов), а потоки мониторить тебе не нужно, так как достаточно повесить событие на закрытие соединения для завершение потока.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 10.11.2008, 19:05
Сообщение #4


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

Спасибо сказали: 5 раз(а)




Репутация:   0  


Litkevich Yuriy, customEvent потому что хочу всё что относится к каждому сокету вывести в поток этого сокета. дабы не вешать главный поток при ддос атаках. а как я понял, система сигнал\слот выполняет код в главном потоке...


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

вообщем то я думаю даже не нужно заталкивать класс потоков в QVector...
надо просто как то присваивать каждому сокету=потоку свой ИД и по этому ИДу иметь возможность послать данные в поток, где открыт сокет. притом так, чтобы они обработались именно в дочернем потоке (где сокет открыт).

вот в том как это правильнее сделать и есть мой вопрос =)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 10.11.2008, 19:16
Сообщение #5


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9642
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(512es @ 10.11.2008, 22:05) *
а как я понял, система сигнал\слот выполняет код в главном потоке...
про это не скажу, так как сам еще не пробывал, но вроде слот выполняется там, где его собственный объект.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 11.11.2008, 0:19
Сообщение #6


Мастер
******

Группа: Модератор
Сообщений: 3283
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Цитата(Litkevich Yuriy @ 10.11.2008, 19:16) *
но вроде слот выполняется там, где его собственный объект.
В том потоке в котором был создан объект получатель.
Цитата(512es @ 10.11.2008, 19:05) *
дабы не вешать главный поток при ддос атаках.
Тогда тебе нужно отказаться от схемы "1 соединени - 1 поток", а подумать о реализации схему "много соединений - 1 поток". Например в винде можно обрабатывать в одном потоке 64 соединения, в никсах не знаю сколько, но думаю, что не меньше...

Да и то это поможет при маленьком DDOS'ике, при серьезном, когда порядка 100 000 соединений к тебе идет у тебя тупо не хватит ресурсов для обработки.

Что-то ты зациклился на ID соединений, чем тебе не нравится указатель на соединение? Что ID 4 байта, что указатель 4 байта, только с указателем нужно меньше телодвижений чем с ID. :)

Список соединений тебе скорее всего понадобится, иначе где класс менеджер соединений будет хранит указатели на соединения?
Класс менеджер соединений должен быть синглтоном, надеюсь не нужно объяснять почему.
При установке соединений сервер создает указатель на него, который помещает в менеджер соединений.
При закрытии соединения посылается сигнал менеджеру соединений для того, чтобы он удалил из списка данное соединение, и если соединение было последним в потоке, то завершать поток (в это случае нужно предусмотреть на нагруженном сервере пул потоков, чтобы не тратить системные ресурсы на создание новых потоков).
И прочее...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 11.11.2008, 11:53
Сообщение #7


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

Спасибо сказали: 5 раз(а)




Репутация:   0  


Цитата(ViGOur)
В том потоке в котором был создан объект получатель

я провёл эксперимент:
прямо в секции run() потока подключаю сигнал readyRead() с сокета, на слот onReadyRead(), который в том же потоке.
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));

в onReadyRead() дописываю замкнутый цикл forever;

запускаю Winternals Process Explorer и смотрю какой из потоков нагружен. как ни странно загружен главный поток..

пока писал этот пост пришла на ум попробывать вот так:
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()),Qt::DirectConnection);


с Qt::DirectConnection слот onReadyRead() отрабатывает в дочернем потоке =)
и главное, при подвисшем потоке сервер продолжает принимать соединения и отвечать другим пользователям =)

Цитата(ViGOur)
Тогда тебе нужно отказаться от схемы "1 соединени - 1 поток", а подумать о реализации схему "много соединений - 1 поток".

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

таким образом хочу максимально изолировать пользователей друг от друга. планируется около 1-2 тыс авторизированых пользователей. мм.. можно ли создать такое колличество потоков?

хранить указатель на соединение это конечно удобно.. а как лучше сделать если всётаки 1 поток = 1 соединение?)

сам себе отвечу =)
http://rsdn.ru/archive/vc/issues/pvc064.htm
Таким образом максимальное количество потоков, которые можно создать при всех параметрах заданных по умолчанию, равняется примерно 2035
Все сказанное ниже справедливо для линейки Windows NT/2000/XP

для линукса наверное будет другое колличество, но думаю мне хватит =)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 11.11.2008, 13:23
Сообщение #8


Мастер
******

Группа: Модератор
Сообщений: 3283
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Цитата(512es @ 11.11.2008, 11:53) *
а как лучше сделать если всётаки 1 поток = 1 соединение?)
Все также, только схема другая...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 11.11.2008, 15:05
Сообщение #9


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9642
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Мысль в слух:
Нельзя ли сделать один поток для авторизации, и группу потоков для авторизованых пользователей, т.е. когда несколько соединений, например 10, крутятся в одном потоке, если авторизованый пользователь начнет гадить, то навредит только десятерым, а остальные нормально работают.

Вобще в юниксах обычно делают одно соединение - один процесс, админы говорят, что так удобнее следить, и когда явно надо кого-то сбросить, то вот его Id, вот его и будем Килл.

(в Unix-системах нет разделения понятий поток/процесс, там всё - потоки. Процессом обычно называют главный поток программы.)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 12.11.2008, 0:43
Сообщение #10


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

Спасибо сказали: 5 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy)
если авторизованый пользователь начнет гадить, то навредит только десятерым

потенциальная дыра.. таким способом можно по 9 пользователей убивать за заход =)

значит, вместо QVector теперь использую QHash (быстрее икать пользователя по иду)
дочерние потоки очень хорошо и удобно передают данные главному через customEvent. мало того, евенты складываются в очередь и это тоже меня устраивает. т.е. обрабатываются в порядке поступления.

а вот отправка данных потоку не получается у меня как надо..
если вызывать метод напрямую через указатель на поток, хранящийся в QHash они выполняются всё равно в главном потоке.
если эмитом вызывать слот результат такой же

через сигнал\слот что то не получилось, т.к. надо передать ещё несколько переменных..

пробовал в дочерние потоки вставлять обработчик customEvent, эвенты приходят но всё равно выполняются в главном потоке =(

в результате отсылка пакета 100 пользователям происходит очень долго. не смотря на то что они все подключались через локалхост.

было бы идеальным быстро распарралелить по всем потокам процедуру отправки пакета по tcp не ждать отправки каждого..

завтра попробую в класс дочерних потоков добавить некую очередь, защищённую мьютексом, в которую буду добавлять пакеты, ожидающие отправки..

ииии... как то всётаки надо сообщить потоку о том что пора отправлять пакет =(

не пойму, почему я не могу из родительского потока пробиться в дочерний??
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V   1 2 3 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 19.8.2018, 9:35