| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Сети > boost::asio |
| Автор: Kirgston 26.2.2011, 09:24 | ||
Всем доброго времени суток! Собственно изучаю данный сабж и пытаюсь написать сервер какой должен отвечать на запросы и всё такое. Сервер будет работать не(!) с клиентами написаными на asio , хотя что то мне подсказывает что разницы быть не должно. Но у меня появилась проблема... коннекты сервер принимает , а вот с обменом сообщений - туго. Для теста использовал ранее написаную утилиту которая просто отправляет и читает пакет в ответ. Суть в том что коннект происходит нормально, и моя утилита сразу же отправляет сообщение и ждет другое сообщение в ответ. Но сервер (на бусте) вообще не вызывает handle_read , а точнее вызывает только когда утилита по таймауту дисконектится . Вот и не понимаю что у меня не так...
Благодарю всех и каждого в помощи изучения этого не простого дела! |
| Автор: Kirgston 26.2.2011, 18:37 |
| На сколько я понимаю проблема в async_read_until. Подставлял просто "\r\n" но ничего не менялось. Не понимаю почему "оно" не видит конца пакета |
| Автор: boostcoder 27.2.2011, 02:30 |
а он(конец пакета) есть? если есть сложность с просмотром пакетов, то рекомендую почитать это: http://www.boost.org/doc/libs/1_46_0/doc/html/boost_asio/reference/async_read_until/overload4.html Добавлено через 2 минуты и 33 секунды нет ни малейшей надобности в нескольких io_service`ах. в вашем случае точно нет. |
| Автор: boostcoder 27.2.2011, 10:50 | ||||
в одном из своих проектов, я, при использовании одного io_service`а и пула потоков, достиг ~178000 запросов-ответов от 6800 юзеров онлайн, в секунду ;) это как пример того, что кол-во io_service`ов ни коим образом не влияет на производительность. я бы даже сказал наоборот. пошли два пакета подряд. ради теста. и еще, перейди по ссылке и почитай. такой способ очень удобен для отладки. Добавлено @ 10:52
в этом ты прав. но это не значит что кол-во io_service`ов или рабочих потоков должно равняться кол-ву одновременно пришедших пакетов. |
| Автор: Kirgston 27.2.2011, 10:59 | ||
впечатляет конечно =) , вот именно , примерно, такое мне и надо Пробовал, нивкакую =). Есть большое подозрение... дело в том что у меня например создается 4 нити в которых идет обработка сообщения. Так вот... что то мне подсказывает что там просто дезлок. То есть при коннекте считывание разрешается только одной нити. Вот мне и кажется что когда идет коннект то одна нить переходит в работу с клиентом, а другая хочет считывать дальше сообщения. Вот и получается дезлок. |
| Автор: boostcoder 27.2.2011, 11:24 | ||
это: http://www.boost.org/doc/libs/1_46_0/doc/html/thread/thread_management.html#thread.thread_management.threadgroup конечно, это не пул, а просто группа потоков. но для большинства задач подходит.
не понял. |
| Автор: Kirgston 27.2.2011, 12:26 | ||
хмм... почитал... но если я не ошибаюсь это просто обертка над потоками? И по сути там нету ни задания для потоков на установку в очередь пула для обработки некой ф-ции, ни автоматического расширения кол-ва потоков и автоматического анализа сколько надо создать тредов. По сути это всё на плечи программиста . И выходит что если без танцов с бубном то 1 клиент = 1 нить, верно? Или я чего то не допонимаю? |
| Автор: boostcoder 27.2.2011, 16:57 | ||||
http://www.boost.org/doc/libs/1_46_0/doc/html/thread/thread_management.html#thread.thread_management.threadgroup.create_thread
да, этого нет. угу. но вы торопите события. об этом можно думать тогда, когда проект написан и работает.
не верно. читайте: http://forum.vingrad.ru/index.php?showtopic=323504&view=findpost&p=2306244 |
| Автор: Kirgston 27.2.2011, 22:18 | ||||
спасибо =) с пулами будем разбиратся Начал делать по Вашему совету... но в ходе процесса появилось множество вопросов(увы но мануал еще больше завел в тупик) 1) почему не работает данный код:
Писал по примеру из http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/deadline_timer.html . Вся разница в классе, не более. Ошибка на стадии компиляции: ">c:\users\алекс\documents\visual studio 2010\projects\asioserver2\asioserver2\main.cpp(93): error C3867: session::OnTimeOut: в вызове функции отсутствует список аргументов; используйте "&session::OnTimeOut" для создания указателя на член" По сути мне просто надо сделать таймер в котором буду проверять пришел ли ответ от клиента или же он "уснул" . И если уснул то надо закрыть связь. 2) как можно настроить max_connections? Ибо это увы, константа :( Или для решения вопроса о максимально допустимом числе одновременных коннектов надо писать свой счетчик? 3) как можно узнать тот же IP, TTL и все прочие прелести от входного коннекта? Т.к. , вроде, в tcp::socket ничего интересного не нашел. Благодарю ! |
| Автор: boostcoder 27.2.2011, 22:51 | ||||||
потому что не совпадают ожидаемая сигнатура, и предоставленная вами.
угу
откуда такая надобность? Оо |
| Автор: Kirgston 27.2.2011, 22:57 | ||
Очень простой пример =) . Обыкновенный фильтр входящих IP .
А Вы не подскажите как решить данный вопрос? |
| Автор: boostcoder 27.2.2011, 23:04 |
с IP - понятно. так: asio::ip::tcp::socket::remote_endpoint().address().to_string() c TTL - для чего? boost::bind() |
| Автор: Kirgston 28.2.2011, 09:47 | ||||
Спасибо большое! Жаль что (по крайней мере для меня) это не прямо напоминает то чем оно есть. Ремоут_ендпоинт расшифровывается как удаленная конечная точка, увы но я ожидал чего то более лаконичного Я не имел ввиду именно ТТЛа , это первое что пришло в голову. А так мне интересно было как узнать вообще весь хидер пакета. Чтобы максимально получить информацию о клиенте. Ага, вчера им тоже пытался =) он мне начал орать что я неправильно его использую. Может действительно криво, так что поковыряю. Кстати... я правильно "убиваю" клиента?
this - класс для сессии клиента |
| Автор: boostcoder 28.2.2011, 11:01 |
угу |
| Автор: Kirgston 28.2.2011, 12:54 | ||||
Мда... увы но не додумался. К сож. справка буста далеко не такого качества как МСДН =) а я привык чтобы все в деталях было. А тут ,как по мне, то оно переводится как удаленная конечная точка, собственно что мне не говорит о том что это сокет =) . Ладно высказал своё "фи", хотя если либы которые намного(!) хуже описаны =) . Хардкор одним словом =)) ТТЛ это первое что пришло в голову Спасибо большое =). Очень не привычно что тут весь буст связан между собой. Жаль правда что , опять таки, мануал не шибко хорош. Собственно выдержка из доков:
Увы там ни слова нету что надо передавать кол-во входящих параметров и конечно же ни слова о том что надо передать еще boost::asio::placeholders::error :( . Ладно, не важно =)) разобрался уже =)). Спасиб большое! Но думаю вопросов еще будет много |
| Автор: Kirgston 28.2.2011, 14:41 | ||
Опять таки прошу Вашей помощи... как нормально закрыть сессию клиента? о_О
При вызове деструктора я фактически получаю аксес виолешен. Причем деструктор вызывается не 1 раз... :( причем подряд :( |
| Автор: boostcoder 28.2.2011, 15:06 |
естественно первый: второй: а что за проблема с закрытием сессии - не понял. |
| Автор: Kirgston 1.3.2011, 23:45 | ||||||
| boostcoder, Собственно на сколько я понял там надо использовать умные указатели. Т.к. можно удалить класс а на самом деле еще внутри ядра буста (а именно асио) висит эвент для него, или нечто похожее. Так что я делал shared_from_this().reset; По крайней мере c delete this точно ничего не вышло Собственно те старые проблемы решил. Но теперь мой мозг взрывает одна, на первый взгляд, мелочь. Дело в том что сделал таймер для каждой сессии. По истечению таймера идет разрыв связи и удаление класса (ну некий примитивный антифлуд). Оно всё работает (проверяли). Только когда начали проверять на реальном клиенте то оказалось что ничего не работает. А точнее таймер вылетает с ошибкой. Точнее вызывается мой евент для таймера . Ошибка "Операция ввода/вывода была прервана из-за завершения потока команд или по запросу приложения" и код ошибки 995. Перед этим идет отправка данных. Но я уже пробовал её убирать - бесполезно. Таймаут вызывается, грубо говоря, в точный промежуток времени. То есть не когда попадая а именно после некоторой ф-ции. Только увы кроме отправки данных (которую я так же убрал) там ничего и нету. Вот собственно как у меня таймер настраивается:
Собственно данная ф-ция вызывается всякий раз когда пришел пакет. Хотя у меня и не так много пакетов приходит... всего 3 =) Может проблема в указателях ... поэтому выкладываю еще и метод управления с помощью них: Главная часть:
Кусочек сесии: (там много лишнего поетому всё и не выкладывал)
Все указатели у меня в виде shared_from_this() . Может их не правильно сделал? |
| Автор: boostcoder 2.3.2011, 00:01 | ||||
во первых - это не рационально. обычно подобное реализуется при помощи единственного контейнера состояний, каждый элемент которого, содержит, помимо прочего, переменную содержащую время последней активности. я для этого использую time_t, полученный от time(). так вот... раз в 10 секунд(такой у меня таймаут для определения что клиент тупит/висит), проверяем все временные метки, и ту, которая превысила таймаут - удаляем. этой задачей у меня занимается класс sheduler, который помимо описанного, еще и занимается рассылкой новостей, обновлением статистики в клиентской программе, банера, чата, и всякой ерундой.
это, пожалуйста еще раз, без эмоций ;) зы код сейчас гляну... Добавлено @ 00:02 член какого класса? Добавлено @ 00:04
тут дважды создаете объект сессии. используйте второй способ ;) Добавлено через 6 минут и 49 секунд в хэндлерах, в else-блоках, сделайте вывод в консоль, или в лог. в остальном ничего критичного не заметил. Добавлено через 8 минут и 57 секунд из конструктора и деструктора объекта сессии, тоже сделайте вывод. это позволит видеть моменты создания и удаления сессий. Добавлено через 10 минут и 28 секунд в данной модели сессии, так и должно быть. Добавлено через 12 минут и 10 секунд в примере, конструктор сессии был приватным, если не ошибаюсь. это для того, чтоб объекты сессии создавались только при помощи ее статической функции create() |
| Автор: Kirgston 2.3.2011, 00:17 | ||||
совершенно согласен. Но как тогда? Создавать тот же вектор или список с указателями на классы и скажем раз в 10 секунд пробегаться по всем существующим классам? Просто вызывается OnTimeOut
в котором error != NULL, а собственно и произошла где то ошибка. Почему? знать не знаю :(. Собственно код ошибки приводил выше. session опс... банальная очепятка. Второй и используется. Первый закоментирован П.С. добавил файлик который отвечает за обработку. Собственно в нем все и проблемы. Буду очень признателен если посмотрите! |
| Автор: boostcoder 2.3.2011, 00:23 | ||||||
угу. это все же лучше чем по таймеру на каждого юзера. при том, в моем варианте, sheduler занимается ищи всякой другой работой, так же, без дополнительный таймеров. никогда не сравнивал boost::system::error_code с NULL. но подозреваю, что происходит сравнение с нулем. достаточно просто if ( error ) { значит есть ошибка } посмотрю. Добавлено через 2 минуты и 27 секунд в начале файла есть такое:
скажите, в реальном коде все так же? Добавлено через 8 минут и 30 секунд в session, убери все строчки: shared_from_this().reset(); рекомендую почитать: http://www.boost.org/doc/libs/1_46_0/libs/smart_ptr/enable_shared_from_this.html и задуматься над смыслом применения reset() к результату shared_from_this() Добавлено через 10 минут и 26 секунд
не нужно такого делать. почитайте все же приведенную мною ссылку. |
| Автор: boostcoder 2.3.2011, 00:38 | ||||
есть такой метод:
далее его вызов таким образом:
угадайте, на что указывает аргумент AsyncWrite() после выхода из SCConnectResultSend() ? ;) далее, еще 6 раз повторяется та же ошибка. в общем, проще переписать с нуля. Добавлено через 2 минуты и 56 секунд не забываем про спасибо ;) |
| Автор: Kirgston 2.3.2011, 08:56 | ||||||||||
Да, подозреваю что сейчас меня закидают тухлыми яйцами и помидорами
По сути shared_from_this() это и есть *this , если конечно я правильно понял. Просто в одном, уже, горе примере видел такое:
Собственно линк: http://alexott.net/common/asio-notes/test-otpc-conn.cpp.html Вот я и...
Читал... просто буст достаточно велик и не всё сразу понимаю =)), тогда так? shared_from_this()->Stop(); . Тогда что, все вызовы с этого же класса (this) переделать в shared_from_this() ?
Честно , хоть убейте не понимаю...
Собственно мы же сначала берем адрес а потом ставим на этот адрес указатель на unsigned char. Вроде всё законно . Да и размер нормально передается. Или опять таки shared_from_this()->AsyncWrite ? Хотя не шибко понимаю... ведь shared_from_this() указывает на this... или я не прав? Может, но для начала лучше понять как правильно писать |
| Автор: boostcoder 2.3.2011, 09:18 | ||||||||
да, запихни в класс. переменные, которые доступны нескольким сессиям, и которые могут изменяться, защити от промежуточного состояния.
про бложек уже писал ;) shared_from_this() создает новый смарт-поинтер на this, тем самым инкрементируя счетчик ссылок. применяя к результату вызова shared_from_this(), reset() - происходит декрементирование. т.е. смысла в этом выражении ноль!
после выхода из SCConnectResultSend(), указатель, указывает в никуда ;) size - да, содержит правильный размер только потому, что он передается по значению. в общем решается это так:
Добавлено через 13 минут и 45 секунд Up. |
| Автор: Kirgston 2.3.2011, 09:35 | ||||
А как тогда удалить класс ? =))) вручную останавливать все коллбеки , закрывать всё всё всё и потом delete this? O_o
Ну... и да и нет =). Почему? Говорю только то что вижу =). Собственно когда вызывается this->AsyncWrite(pMsg); деструктор, грубо говоря, функции еще не вызван. И те объекты еще живут. Насколько я понимаю (конечно я могу и заблуждаться). Данные объекты не видны за пределами этой ф-ции. Но ведь где то в памяти для них выделено место, верно? И если есть права записи\чтения из этой области то я думаю что спокойно можно поставить указатель. Конечно, если поставить брейкпоинт на AsyncWrite то в data будет только первый символ. Но я предполагаю что там так же идет нечто типа memcpy(buf,(void*)&data,len); или что то такое. Т.к. я проходился сниффером пакетов и там четко видно что все пакеты приходят именно "как надо" =). То есть полностью. Значит внутри всё норм? Правда для теста сейчас вообще удалю AsyncWrite и забабахаю отправку в каждой ф-ции. Быдлокод конечно... но что поделать? надо же понять почему таймер так начинает сбоить... (хотя если честно то у меня и на одном коннекте он сбоит... ) |
| Автор: boostcoder 2.3.2011, 09:43 | ||||||||||
объект сам удалится ;)
когда вызываешь - да. но когда выходишь из SCConnectResultSend(), на что они указывают? ;) а так как ты вызываешь асинхронную операцию, она вернет управление сразу, а реальная запись данных произойдет несколько позже. потому http://www.boost.org/doc/libs/1_46_0/doc/html/boost_asio/overview/core/buffers.html#boost_asio.overview.core.buffers.buffer_debugging:
нет. данные находятся на стеке, и валидны до выхода из блока.
бессмысленное занятие, правда. Добавлено через 3 минуты и 23 секунды вот конкретный пример из доки:
даже название функции соответствующее ;) |
| Автор: Kirgston 2.3.2011, 10:35 | ||||||
Хм.. тогда надо вызвать socket_.shutdown + socket_.close? Или просто socket_.shutdown ? Кстати... вот эти умные указатели... они же наверно кучу ресурсов жрут? =)
Да, что то не подумал... увы Собственно создал шаблон, но мучают сомнения что он опять крив
т.к. опять таки указатель на память... но как иначе? Мне ведь надо как то структуру переделать в набор данных. Или еще до вызова AsyncWrite переделать в UCHAR и повесить умный указатель?
Не увидел Очень извиняюсь, просто уже путаться начал |
| Автор: boostcoder 2.3.2011, 10:42 | ||||
при разрушении объекта сессии, сокет закроется в любом случае, потому что он является членом сессии. не то чтобы много...но жрут. смарт-поинтер передаваемый в шаблон, передай его дальше в хэндлер. это: так:
правильно, это делается при помощи сериализации ;) |
| Автор: Kirgston 2.3.2011, 14:05 | ||
Само собой. Но если напрямую нельзя вызвать delete this из-за возможных побочных эффектов, тогда как? Ага, с этим уже раз работал =) правда я так юникод передавал =)) чтобы не заморачиватся с разбиением и переделываем юникода в массив тех же UCHAR использовал сериализацию. Кстати тогда Вы тоже помогли с примером Добавлено через 14 минут и 20 секунд По сути на счет дисконнекта и разрушения объекта я имею такие предположения: 1) delete this . Но кажется что это чревато. Класс удалится, но в ядре асио может остаться коллбек или что то такое на выделенную область памяти под класс. В итоге акксес виолейшен 2) socket_.close \ socket_.shutdown . Я не знаю как работает асио внутри... но при дисконекте вызванном самим клиентом то автоматически разрушается и класс. Вот собственно и появилась мысля... что если разорвать связь то автоматически и закроется класс 3) shared_from_this().reset . Вроде оно освобождало... ну по крайней мере рамка прыгала с 8мб до 5 и обратно =). Хотя могу ошибаться... Собственно вот такие вот мысли ... а что из этого верно? =) извините за тупость, просто пока только учусь и множество вещей понимаю именно с видимого результата и чисто своих предположений |
| Автор: boostcoder 2.3.2011, 17:30 | ||
так:
|
| Автор: Kirgston 5.3.2011, 19:06 |
| Всё спасибо. Кстати на будущее. socket_.cancel(); socket_.close(); На Вин ХР делать низя =). Вин 7 воспринимает нормально а ХР нет. Лучше просто сделать шатдаун тогда и сокет сам закроется ;). |
| Автор: boostcoder 5.3.2011, 19:20 |
| ... |