Название: Таймауты в многопоточном клиент-серверном приложении. Отправлено: pawok11 от Март 02, 2010, 17:23 Есть клиент-серверное приложение. В клиенте создается несколько потоков, от 1-2 до 5-7.
В каждом потоке производится tcp-подключение, отсылка пакета запроса и прием пакета ответа. На клиенте есть очередь запросов. Каждый запрос характеризуется ip, портом и данными для отправки. Таких запросов порядка 15 (число запросов может быть больше). Запросы генерируются по времени (обязательное условие генерации одинаковых запросов раз в определенный промежуток времени). Если запрос есть в очереди запросов, то он туда не ставиться. Создается пул потоков (например 5) для обработки этой очереди запросов. Если поток свободный, в поток передается запрос на обработку. Если свободных потоков нет, то запрос ставиться в очередь ожидающих на отправку. Диспетчер пула клиентов Код:
Поток обработки клиента Код: void TcpClientThread::run() Со стороны сервера запущен QTcpServer. Вообще таких серверов может быть несколько, работающих по разному принципу. На каждое входящее сообщение создается свой собственный поток обработки. Диспетчер сервера Код: void DispatcherServerThread::run() Поток обработки входящего соединения на сервере Код: void TcpServerThread::run() Ситуация складывается следующая. в первое время все работает нормально. Через какое-то время в клиенте начинает срабатывать таймаут подключения. Потом соединение проходит и данные приходят. Такое "мигание" (то есть данные, то таймуат) продолжается какое-то время где около часа. Потом все время начинает срабатывать таймаут подключения. Почему начинают срабатывать таймуаты? Название: Re: Таймауты в многопоточном клиент-серверном приложении. Отправлено: BRE от Март 02, 2010, 17:39 Что бросилось в глаза.
Код
Это не гарантирует, что пришел весь пакет с данными. Одна сторона послала 10Кб, вторая получила первую партию блока (2Кб), произойдет выход из waitForReadyRead и ты вычитываешь только часть данных. Название: Re: Таймауты в многопоточном клиент-серверном приложении. Отправлено: pawok11 от Март 02, 2010, 17:52 Пока порядок передаваемых данных 100-200 байт и это не должно влиять.
А где можно почитать про то как это обработать? Название: Re: Таймауты в многопоточном клиент-серверном приложении. Отправлено: niXman от Март 02, 2010, 18:23 pawok11, для вашей задачи абсолютно не подходят блокирующие сокеты. т.к. уничтожают всю идею.
я про это: Код и подобное. наверное можно каким-то боком, используя Qt, нормально решить задачу. но что-то сомневаюсь. много оверхеда нужно написать. смотрите лучше в сторону boost.asio. эта либа спроектирована именно для задач подобного рода. Название: Re: Таймауты в многопоточном клиент-серверном приложении. Отправлено: SABROG от Март 02, 2010, 23:15 Если свободных потоков нет, то запрос ставиться в очередь ожидающих на отправку. Неправильное решение как минимум по двум причинам. Как только установлено соединение начинается отсчет, обычно 60 секунд. Если в течении этого времени никаких данных не приходит, то сокет отключается операционной системой, дабы не подвергать машину возможной атаки (syn-flood например) и дать другим клиентам возможность подключиться. Причем таймауты могут стоять как на стороне сервера так и на стороне клиента. Мне например пришлось редактировать настройки Firefox и сервера на работе, чтобы браузер мог дождаться данных от PHP скрипта. Правда я столкнулся с неприятной особенностью таймаутов, если поставить слишком большой значение, скажем 1 час, то сервер все равно никогда не ответит, даже если будет готов через 1 секунду. До сервера может запрос тупо не дойти. Причем если поставлю таймаут 5 минут, то соединение обрывается до того как PHP скрипт успевает полностью отработать. Да еще архитектура кривая, не поддерживает докачку и каждый раз начинает всё заново. Короче без нормального собственного протокола будут проблемы. Если нужно долго поддерживать связь между двумя сокетами, то нужно реализовывать PING-PONG опкоды, чтобы каждая из сторон знала, что его собеседник еще жив. Если PONG долго не приходит, то вот это уже явный таймаут. Никто не оставляет открытым подключение, чтобы оно сидело и ждало своей очереди. Обычно реализуют переподключение (дозвон) и количество попыток (или бесконечный). Поэтому для твоей задачи достаточно жестоко закрывать сокеты "лишних" клиентов. Но для начала нужно им послать рекомендуемое время для переподключения основанное на позиции в очереди, чтобы все клиенты не ломанулись сразу на сервак и тем самым его угробили. У клиентов сделать настройки "использовать рекомендуемое время переподключения", "использовать пользовательское время переподключения". void QTcpServer::setMaxPendingConnections ( int numConnections ) - не используй, ОС может мурыжить сокеты еще долго не закрывая, лучше уж сделать это самому. Конечно от "waitForReadyRead" надо отказаться в пользу событий. Неблокирующие сокеты используют метод WSAAsyncSelect, который использует систему сообщений Windows. Qt использует WSAAsyncSelect для получения сообщений от ОС и Overlapped I/O API, который в теории позволяет подключаться до 10000 (http://tangentsoft.net/wskfaq/advanced.html#maxsockets) клиентам на один сервер. Для Windows asio/boost::asio используют этот же механизм, но они не используют WSAAsyncSelect, а вместо него используют IOCP (Completion Port). Насколько я знаю это более предпочтительно, особенно для приложений без окон. Т.е. разница в доставке сообщений от ОС. Топик конечно старый, но на всякий случай прилагаю (http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.networks/2004-09/0111.html), человек спрашивает чем лучше IOCP по сравнению WSAAsyncSelect. Как бы там ни было система доставки сообщений не влияет на скорость скачивания, так как не приходит на каждый байт данных, при соответствующем размере буффера. Тем не менее я собираюсь написать suggestion троллям на перевод в сторону IOCP. Если у тебя хватит запалу, то я бы с удовольствием посмотрел на реализацию одного и того же сервера с применением Qt и asio. Еще бы понять где найти столько клиентов со всего мира, чтобы проверить нагрузку, скорость, стабильность и тому подобное. Название: Re: Таймауты в многопоточном клиент-серверном приложении. Отправлено: pawok11 от Март 03, 2010, 11:45 Цитировать Если свободных потоков нет, то запрос ставиться в очередь ожидающих на отправку. Я, наверное, не четко сформулировал. "очередь ожидающих на отправку" это просто очередь, где храняться данные (ip, порт и данные для отправки). Здесь не создаются сокеты. Сокеты создаются только в потоке, когда появляется свободный поток. Весь механиз кратко описать можно так. Появляется свободный поток, создается соединение, отсылается запрос, получается ответ, соединение закрывается, высылается сигнал, что поток свободен. Не совсем правильно так делать, потому что соединение почти все вермя происходит с одними и теми же абонентами, но так как помимо tcp по такой же схеме используется еще, например, udp (и др.), то в целях универсализации была выбрана такая схема. Еще важно, что заранее не известен адрес сервера, к которому будет обращаться клиент. |