crossplatform.ru

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

5 страниц V  « < 2 3 4 5 >  
Ответить в данную темуНачать новую тему
> Обрыв соединения QTcpSocket
OrSOn
  опции профиля:
сообщение 19.2.2010, 13:26
Сообщение #31


Студент
*

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

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




Репутация:   0  


Изначально так и планировалось, чтобы на 1 запрос 1 поток... Но суть в чем. Имеется система для передачи больших объемов информации (обновления данных по сети). Причем данные могут быть разнотипными (с разными приоритетами). В итоге имеем большое число возможных одновременных подключений. Если создавать отдельные потоки для каждого соединения, то их может стать слишком много и передача "умрет", будет разом обновляться у всех, но ОЧЕНЬ медленно (не из-за сети, так из-за скорости чтения с жесткого диска). Поэтому было принято решение создать заранее ограниченное количество потоков, а все запросы от клиентов распределять между ними, но не просто так, а на передачу 1 файла, т.е. клиент подключился и попал в очередь. Дошла очередь до него - сокет отправлен в поток, передается ОДИН файл и сокет попадает обратно в очередь, а потоку передают следующий. Так сделано из-за приоритетов... Если давать возможность загружать сразу все файлы, то просто приоритетные запросы файлов, необходимых срочно, будут ждать очень долго... А если создавать по одному потоку на передачу одного файла одному клиенту - это будет глупо, по-моему..

З.Ы. нагорожено там из-за некоторых дополнительных требований, они тут ни при чем)))

Цитата(SABROG @ 19.2.2010, 13:19) *
Смотри что получается. Сокет находится в гуишном потоке, его обслуживает отдельный поток, это означает, что когда ты вызываешь метод write() ты напрямую обращаешься к методу объекта. В результате ты пытаешься записать данные из одного потока в другой напрямую.

Если ты не хочешь переносить сокет в тот же поток, который его обслуживает, то убедись, что обслуживающий поток эмитит сигнал о начале записи каких-либо данных и продолжает своё выполнение в то время, когда основной поток что-то пишет в сокет. Если ты все-таки хочешь вызывать read/write в обслуживающем потоке, то сокет должен принадлежать ему. Просто запомни, что любое взаимодействие между двумя объектами находящимися в разных потоках должно происходить через сигналы или события. Не должно быть никаких прямых вызовов методов одного объекта у другого. Конечно ничего не случиться, если метод threadsafe, но таковыми являются не все.


Я не могу отдавать сокет обрабатывающему потоку, ибо потом он возвращается в главный и может быть передан затем другим... А вот насчет передачи сигналов - если так получится, то будет круто, надо попробовать)))
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 19.2.2010, 13:45
Сообщение #32


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

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




Репутация:   34  


Задача потока выполнять долгую операцию на фоне позволяя работать пользователю без блокировки интерфейса. Если сокет будет находится в главном потоке да еще и write() использовать, то какой смысл в отдельном потоке? write() и read() неблокирующие методы и возвращаются моментально.

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

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

Сообщение отредактировал SABROG - 19.2.2010, 13:47
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 19.2.2010, 13:48
Сообщение #33


Студент
*

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

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




Репутация:   0  


Вот я и думал об этом как раз, чтобы обрабатывающие потоки просто главному пересылали массивы информации, считанной из файла, а он уже отсылал...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 19.2.2010, 14:03
Сообщение #34


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

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




Репутация:   44  


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

Возможно, все равно придется использовать пул потоков. В Qt уже есть их реализация, посмотри на QThreadPool и QRunnable.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 19.2.2010, 14:05
Сообщение #35


Студент
*

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

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




Репутация:   0  


Ок, спасибо, буду ждать)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 19.2.2010, 14:37
Сообщение #36


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

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




Репутация:   34  


Думаю вместо того, чтобы данные передавать с сигналом можно использовать кольцевой буффер (circular buffer, ring buffer). Можно посмотреть как он реализован в Wait Conditions Example.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 19.2.2010, 15:06
Сообщение #37


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

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




Репутация:   44  


Цитата(SABROG @ 19.2.2010, 14:37) *
Думаю вместо того, чтобы данные передавать с сигналом можно использовать кольцевой буффер (circular buffer, ring buffer). Можно посмотреть как он реализован в Wait Conditions Example.

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

OrSOn
Вот новый архив, асинхронный сервер лежит в server-async. Для работы используется QSocketNotifier.

Сообщение отредактировал BRE - 19.2.2010, 15:36
Прикрепленные файлы
Прикрепленный файл  network.tar.gz ( 2,43 килобайт ) Кол-во скачиваний: 303
 
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 19.2.2010, 16:19
Сообщение #38


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

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




Репутация:   34  


Цитата(BRE @ 19.2.2010, 15:06) *
А если принимающая сторона (клиент) сидит на узком канале и не успевает выбирать данные, которые ему пихают.


В общем QIODevice и так использует QRingBuffer (internal class), поэтому можно просто завести буфер на базе QByteArray для каждого сокета, ловить сигнал bytesWritten() и просить (emit signal) поток подгрузить новую порцию данных, если клиенту были отправлены все данные. Поток сам очистит буффер и поместит следующий блок, затем оповестит (emit signal) об этом сокет. Сокет уже их будет писать, а поток продолжит читать данные из файлов для других сокетов и эмитить им сигналы как прочитает.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 19.2.2010, 16:53
Сообщение #39


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

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




Репутация:   44  


Цитата(SABROG @ 19.2.2010, 16:19) *
В общем QIODevice и так использует QRingBuffer (internal class), поэтому можно просто завести буфер на базе QByteArray для каждого сокета, ловить сигнал bytesWritten() и просить (emit signal) поток подгрузить новую порцию данных, если клиенту были отправлены все данные. Поток сам очистит буффер и поместит следующий блок, затем оповестит (emit signal) об этом сокет. Сокет уже их будет писать, а поток продолжит читать данные из файлов для других сокетов и эмитить им сигналы как прочитает.

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

Хотя... Если bytesWritten отправляется только после реальной отправки данных, то все будет нормально. Полез смотреть. :)

Да, вместо QSocketNotifier можно использовать сигнал bytesWritten().


Сообщение отредактировал BRE - 19.2.2010, 17:10
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 24.2.2010, 10:30
Сообщение #40


Студент
*

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

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




Репутация:   0  


Спасибо, сейчас буду пробовать все посоветованное..))
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 4.12.2024, 13:03