Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.191.189.120] |
|
Сообщ.
#1
,
|
|
|
К сожалению буст для меня это непонятный темный лес.
Нужен ваш хелп. Сервер у меня многопоточный. Но я правильно понимаю что объект boost::asio::io_service должен быть один единственный в приложении? В каждом потоке достаточно вызвать io_service.run(); правильно? Тут у меня возникает первая затыка. Которую я пока не знаю как решить. Мне необходимо в каждой асинхронной операции будь то чтение или запись знать в каком потоке она вызвалась. у меня имеется обертка над потоком - свой класс workerThread. При старте сервера я создаю ХХХ объектов workerThread и у каждого такая потоковая функция void workerThreads::workingThread( ) { server s( io_service, m_serverport ); io_service.run(); } |
Сообщ.
#2
,
|
|
|
Вызывай GetCurrentThreadId(). Или тебе нужен конкретный указатель на объект workerThread? Тогда можно сделать глобальную мапу ThreadId -> workerThread
|
Сообщ.
#3
,
|
|
|
Или так:
__declspec(thread) workerThreads* WorkerThread = nullptr; ... void workerThreads::workingThread( ) { WorkerThread = this; server s( io_service, m_serverport ); io_service.run(); } |
Сообщ.
#4
,
|
|
|
Цитата Pacific @ Вызывай GetCurrentThreadId(). Или тебе нужен конкретный указатель на объект workerThread? Тогда можно сделать глобальную мапу ThreadId -> workerThread Я к этому "решению" и пришел. workerThread** m_threadsmap = NULL; m_threadsmap = new LPWORKERTHREADPTR[ 0x10000 ]; memset( m_threadsmap, 0, sizeof(LPWORKERTHREADPTR) * 0x10000 ); и заношу в массив указатель на потоковый объект по его id перерасход памяти есть но зато мгновенный доступ в отличие от std::map for (int i = 0; i < numberOfThreads; i++) { workerThread* th = new workerThread( m_dbpool, io_service ); int threadid = th->createThread( getServerPort()); m_threadsmap[ threadid ] = th; } Я сделал "опасное" допущение что ID потока в 32 битной windows не превысит 0хFFFF - лично я ни разу не сталкивался чтобы оно было больше 0x4000 далее в одном и потоков куда меня коллбэк boost.asio выкинул такой вот код: int threadid = GetCurrentThreadId(); workerThread* th = m_threadsmap[ threadid ]; вопрос в том - насколько по корану данный сабж. и не является ли мега кривыми костыялми. может быть у буста есть фича чтобы в коллбэк передать какие то данные о потоке в котором он вызвался. |
Сообщ.
#5
,
|
|
|
progman
Это костыль, да. Лучше переделай на thread local глобальную переменную (пост №3) - доступ также мгновенный, только перерасхода памяти не будет, и не будет зависеть от предположений о threadid. |
Сообщ.
#6
,
|
|
|
Цитата Pacific @ progman Это костыль, да. Лучше переделай на thread local глобальную переменную (пост №3) - доступ также мгновенный, только перерасхода памяти не будет, и не будет зависеть от предположений о threadid. че то я туплю - как мне оно поможет? __declspec(thread) workerThreads* WorkerThread = nullptr; ... void workerThreads::workingThread( ) { WorkerThread = this; server s( io_service, m_serverport ); io_service.run(); } ? |
Сообщ.
#7
,
|
|
|
progman
WorkerThread будет глобальной переменной, но своей для каждого потока. Где надо - получай указатель на свой объект, локальный для текущего потока. |
Сообщ.
#8
,
|
|
|
Решили соскочить с IOCP на буст?
Интересный опыт, поделитесь потом своим мнением - такое сравнение будет очень полезно для всех. |
Сообщ.
#9
,
|
|
|
Цитата Oleg2004 @ Решили соскочить с IOCP на буст? Интересный опыт, поделитесь потом своим мнением - такое сравнение будет очень полезно для всех. под виндой boost::asio через IOCP и работает. Добавлено еще момент, комильфо ли отсылать данные клиенту так: HRESULT connection::send( char* buffer, DWORD length, LPWSAOVERLAPPED lpOverlapped ) { auto self(shared_from_this()); boost::asio::async_write( m_socket, boost::asio::buffer(&length, header_length), [this, self](boost::system::error_code ec, std::size_t /*length*/) { if (!ec) { } }); boost::asio::async_write( m_socket, boost::asio::buffer( buffer, length), [this, self](boost::system::error_code ec, std::size_t /*length*/) { if (!ec) { } }); return S_OK; } сначала шлю 4 байта размер а потом данные. в WSASend можно было два буфера указать и отправить за один вызов. Там оно более эстетично в коде. А как в бусте поэстетичнее? И я надеюсь тут я асинхронную передачу данных делаю :-) |
Сообщ.
#10
,
|
|
|
Цитата progman @ В каждом потоке достаточно вызвать io_service.run(); правильно? Да. Цитата progman @ Мне необходимо в каждой асинхронной операции будь то чтение или запись знать в каком потоке она вызвалась. boost::this_thread::get_id() ? Добавлено Цитата progman @ А как в бусте поэстетичнее? Никогда так не делал. Затрудняюсь сказать, обеспечивает ли буст последовательность исполнения команд из очереди на нескольких потоках. Лучше в обработчике завершения первого write пошли второй. И, скати, почему нельзя отправить сразу 1м пакетом? |
Сообщ.
#11
,
|
|
|
Цитата shm @ Никогда так ты не делал. Затрудняюсь сказать, обеспечивает ли буст последовательность исполнения команд из очереди на нескольких потоках. по идее оно в одном потоке вызывается. сейчас запустил тест - 15 тысяч клиентов третий час нормально пашут. но что то тоже стали сомнения терзать. Хотя с другой стороны мне важно чтобы сначала ушел заголовок пакета - просто 4 байта а потом тело. И не важно из одного потока или из разных. по идее это гарантируется последовательным вызовом... но что там внутри... уже сомнения пошли Цитата shm @ Лучше в обработчике завершения первого write пошли второй. придется выделять память и хранить передаваемый буфер. |
Сообщ.
#12
,
|
|
|
Цитата progman @ boost::asio через IOCP Ну да: #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/scoped_ptr.hpp> #include <boost/asio/io_service.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/timer_op.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_fwd.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/win_iocp_io_service_fwd.hpp> #include <boost/asio/detail/win_iocp_operation.hpp> #include <boost/asio/detail/thread.hpp> #include <boost/asio/detail/push_options.hpp> Такое нагромождение всего чего - не, я лично сторонник АПИ. Все библиотеки подобного рода - это инструмент для RAD (rapid application development) Быстро сбацать и запустить. Очень даже возможно, что и будет неплохо работать - для определенных целей. И, как нам всем понятно - внутри классов буста - все тот же виндовский АПИ... Впрочем это все только ИМХО. Вот тут интересные мысли - вроде по теме. И кстати о проблеме - протокол вида "frame_size->frame_body" |
Сообщ.
#13
,
|
|
|
Посмотрел, последовательность в твоем случае будет соблюдена. Обратил еще раз внимание на твой код, вот так:
Цитата progman @ boost::asio::buffer(&length, header_length) делать нельзя. Т. к. должна обеспечиваться гарантия существования объекта до завершения операции. Другими словами, boost::asio::buffer работает по ссылке. Добавлено Цитата progman @ придется выделять память и хранить передаваемый буфер. Ты так говоришь как будто это так сложно организовать. |
Сообщ.
#14
,
|
|
|
Цитата shm @ делать нельзя. Т. к. должна обеспечиваться гарантия существования объекта до завершения операции. Другими словами, boost::asio::buffer работает по ссылке. спасибо. не учел. Думал там копирование внутри. HRESULT connection::send( char* buffer, DWORD length, LPWSAOVERLAPPED lpOverlapped ) { char* sendbuffer = new char[length + header_length]; memcpy( &sendbuffer[ 0 ], &length, header_length); memcpy( &sendbuffer[ header_length ], buffer, length ); boost::asio::async_write( m_socket, boost::asio::buffer( sendbuffer, length + header_length ), std::bind( &connection::handle_write, shared_from_this(), sendbuffer, std::placeholders::_1, std::placeholders::_2 ) ); return S_OK; } void connection::handle_write(char* buffer, const boost::system::error_code& a_error, std::size_t a_size) { delete[] buffer; } |
Сообщ.
#15
,
|
|
|
Я у себя привязывал буфер данных чтения и записи к объекту, связанному с сокетом. Не скажу, что это самый правильный подход, но рабочий.
|
Сообщ.
#16
,
|
|
|
С чтением вопрос. Гарантирует ли такая конструкция буста что я получу на выходе все данные которые ожидаю получить?
void connection::do_read_body( int datalength ) { auto self( shared_from_this( ) ); m_socket.async_read_some(boost::asio::buffer(m_recvbuffer, datalength), [this, self](boost::system::error_code ec, std::size_t length) { if( !ec ) { //is datalength == length ????? } } } + есть непонятка как остановить io_service прервав во всех потоках прием данных и ожидание коннекта io_service.stop() не обеспечивает остановку всего |
Сообщ.
#17
,
|
|
|
Цитата progman @ Гарантирует ли такая конструкция буста что я получу на выходе все данные которые ожидаю получить? Цитата http://www.boost.org/doc/libs/1_38_0/doc/h..._read_some.html The read operation may not read all of the requested number of bytes. Consider using the async_read function if you need to ensure that the requested amount of data is read before the asynchronous operation completes. Добавлено Цитата progman @ не обеспечивает остановку всего Что это значит? У меня все работает, только нужно дождаться завершения потоков, где вызвана io_sevice.run(). |
Сообщ.
#18
,
|
|
|
Цитата shm @ Что это значит? У меня все работает, только нужно дождаться завершения потов, где вызвана io_sevice.run(). у меня после вызова io_service.stop() крашится все где то внутри буста |
Сообщ.
#19
,
|
|
|
Цитата progman @ у меня после вызова io_service.stop() крашится все где то внутри буста Как потоки создаешь? |
Сообщ.
#20
,
|
|
|
Цитата shm @ Цитата progman @ у меня после вызова io_service.stop() крашится все где то внутри буста Как потоки создаешь? hWorkerThread = CreateThread( NULL, 0, serverPool, this, 0, &dwThreadId ); DWORD WINAPI workerThread::serverPool( LPVOID lpvParam ) { return (( workerThread* )lpvParam)->thread(); } int workerThread::thread( ) { mWorkerThread = this; try { server s( m_dbpool, io_service, m_serverport ); io_service.run(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } |
Сообщ.
#21
,
|
|
|
Цитата progman @ CreateThread попробуй заменить на _beginthreadex. А еще лучше на boost::thread, тогда переходник serverPool и не нужен будет. |
Сообщ.
#22
,
|
|
|
progman, решил проблему?
|
Сообщ.
#23
,
|
|
|
Цитата shm @ progman, решил проблему? нет ( у меня на сервере #include <boost/thread.hpp> вызывает кучу ошибок в компиляции ( windows web server 2008 R2 ) - я приложение собираю на удаленном сервере который полностью идентичен рабочим серверам пула. при этом на моей локальной машине ( windows 10 ) все ок. Студия в обоих случаях 2013 professional Boost билдился с одинаковыми параметрами. Поскольку критической важности нету я пока забил - занимаюсь текучкой ( дрючу оболтусов своих а то расслабились ) Будет время нагуглю как решать траблу а то даже в X-COM 2 поиграть некогда ((( Скрытый текст 1> workerThread.cpp 1>C:\SERVER\LIBS\boost_1_60_0\boost/type_traits/common_type.hpp(111): fatal error C1001: An internal error has occurred in the compiler. 1> (compiler file 'f:\dd\vctools\compiler\cxxfe\sl\p1\c\esumem.c', line 8636) 1> To work around this problem, try simplifying or changing the program near the locations listed above. 1> Please choose the Technical Support command on the Visual C++ 1> Help menu, or open the Technical Support help file for more information 1> C:\SERVER\LIBS\boost_1_60_0\boost/type_traits/common_type.hpp(133) : see reference to class template instantiation 'boost::type_traits_detail::common_type_impl<T1,T2>' being compiled 1> with 1> [ 1> T1=int_least64_t 1> , T2=int_least64_t 1> ] 1> C:\SERVER\LIBS\boost_1_60_0\boost/type_traits/common_type.hpp(139) : see reference to class template instantiation 'boost::type_traits_detail::common_type_decay_helper<T1,T2,__int64,__int64>' being compiled 1> with 1> [ 1> T1=int_least64_t 1> , T2=int_least64_t 1> ] 1> C:\SERVER\LIBS\boost_1_60_0\boost/chrono/duration.hpp(405) : see reference to class template instantiation 'boost::common_type<Rep1,Rep2>' being compiled 1> with 1> [ 1> Rep1=int_least64_t 1> , Rep2=int_least64_t 1> ] 1> C:\SERVER\LIBS\boost_1_60_0\boost/thread/win32/basic_timed_mutex.hpp(211) : see reference to class template instantiation 'boost::common_type<boost::chrono::system_clock::duration,boost::chrono::system_clock::duration>' being compiled 1> SendingList.cpp 1>c1xx : fatal error C1060: compiler is out of heap space 1> Note: non-fatal system error releasing memory (87) 1> basePacket.cpp 1>c1xx : fatal error C1060: compiler is out of heap space 1> Note: non-fatal system error releasing memory (87) 1> tcpConnectionList.cpp 1>c1xx : fatal error C1060: compiler is out of heap space 1> Note: non-fatal system error releasing memory (87) 1> tcp_server.cpp 1>c1xx : fatal error C1060: compiler is out of heap space 1> Note: non-fatal system error releasing memory (87) 1> NotifycationThreads.cpp 1>c1xx : fatal error C1060: compiler is out of heap space 1> Note: non-fatal system error releasing memory (87) |
Сообщ.
#24
,
|
|
|
progman, судя по всему баг VC. Попробуй накати все обновления.
|
Сообщ.
#25
,
|
|
|
Цитата shm @ progman, судя по всему баг VC. Попробуй накати все обновления. уже. MSVC 2013 Update 4 требуется. обновил. Бага исчезла но все равно падает буст когда стоплю. вот код: void CCompletitionPort::closeServer() { io_service.stop(); ::WaitForMultipleObjects( m_threadsEvents.size(), &m_threadsEvents[ 0 ], TRUE, INFINITE); } Логика простая - в каждом потоке создаю эвент который дергаю когда поток заканчивает работу. после остановки сервиса жду когда все потоки закончатся. Но падает все где то в недрах буста ( ни один поток не заканчивается. поэтому сейчас вот такой вот криворукое решение: void CCompletitionPort::closeServer() { exit(0); } |
Сообщ.
#26
,
|
|
|
Цитата progman @ ::WaitForMultipleObjects( m_threadsEvents.size(), &m_threadsEvents[ 0 ], TRUE, INFINITE); wtf? Если ты используешь буст, то там у объекта thread есть метот join для этих целей. Добавлено Цитата progman @ Но падает все где то в недрах буста ( Падает как? Буст кидает эксепшен? И где конкретно падает, стек вызовов-то хоть есть? |
Сообщ.
#27
,
|
|
|
Цитата shm @ Падает как? Буст кидает эксепшен? И где конкретно падает, стек вызовов-то хоть есть? да эксепшен Цитата Unhandled exception at 0x00089DA6 in servervisuald.exe: 0xC0000005: Access violation reading location 0x08B8F7B0. вот стек: Цитата > servervisuald.exe!boost::asio::basic_io_object<boost::asio::socket_acceptor_service<boost::asio::ip::tcp>,1>::get_service() Line 209 C++ servervisuald.exe!boost::asio::basic_socket_acceptor<boost::asio::ip::tcp,boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >::async_accept<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp>,boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > > >(boost::asio::basic_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp> > & peer, boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > > && handler, void * __formal) Line 1019 C++ servervisuald.exe!network::server::accept(int id, const boost::system::error_code & err) Line 39 C++ servervisuald.exe!network::server::handle_accept(network::server * srv, int id, const boost::system::error_code & err) Line 29 C++ servervisuald.exe!boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> >::operator()<void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::rrlist1<boost::system::error_code const &> >(boost::_bi::type<void> __formal, void (network::server *, int, const boost::system::error_code &) * & f, boost::_bi::rrlist1<boost::system::error_code const &> & a, int __formal) Line 398 C++ servervisuald.exe!boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > >::operator()<boost::system::error_code const &>(const boost::system::error_code & a1) Line 1235 C++ servervisuald.exe!boost::asio::detail::binder1<boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > >,boost::system::error_code>::operator()() Line 48 C++ servervisuald.exe!boost::asio::asio_handler_invoke<boost::asio::detail::binder1<boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > >,boost::system::error_code> >(boost::asio::detail::binder1<boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > >,boost::system::error_code> & function, ...) Line 70 C++ servervisuald.exe!boost_asio_handler_invoke_helpers::invoke<boost::asio::detail::binder1<boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > >,boost::system::error_code>,boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > > >(boost::asio::detail::binder1<boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > >,boost::system::error_code> & function, boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > > & context) Line 37 C++ servervisuald.exe!boost::asio::detail::win_iocp_socket_accept_op<boost::asio::basic_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp> >,boost::asio::ip::tcp,boost::_bi::bind_t<void,void (__cdecl*)(network::server *,int,boost::system::error_code const &),boost::_bi::list3<boost::_bi::value<network::server *>,boost::_bi::value<int>,boost::arg<1> > > >::do_complete(boost::asio::detail::win_iocp_io_service * owner, boost::asio::detail::win_iocp_operation * base, const boost::system::error_code & result_ec, unsigned int __formal) Line 142 C++ servervisuald.exe!boost::asio::detail::win_iocp_operation::complete(boost::asio::detail::win_iocp_io_service & owner, const boost::system::error_code & ec, unsigned int bytes_transferred) Line 46 C++ servervisuald.exe!boost::asio::detail::win_iocp_io_service::do_one(bool block, boost::system::error_code & ec) Line 406 C++ servervisuald.exe!boost::asio::detail::win_iocp_io_service::run(boost::system::error_code & ec) Line 164 C++ servervisuald.exe!boost::asio::io_service::run() Line 59 C++ servervisuald.exe!network::workerThread::workingThread() Line 59 C++ Добавлено Цитата shm @ wtf? Если ты используешь буст, то там у объекта thread есть метот join для этих целей. ну а как я еще в другом потоке узнаю что все рабочие потоки закончились - имхо только через в каждом потоке SetEvent + WaitForMultipleObjects я же говорю буст я практически не знаю. А усиленно разбираться нету времени ( Цитата Oleg2004 @ Пару слов - как впечатление...Все думаю тоже скачать и попробовать любимую игру в новом виде...Кстати у вас стимовский вариант? не знаю. На стиме купил но играть некогда. |
Сообщ.
#28
,
|
|
|
Цитата progman @ ну а как я еще в другом потоке узнаю что все рабочие потоки закончились - имхо только через в каждом потоке SetEvent + WaitForMultipleObjects io_service.stop(); for(auto th : ThreadList) { th->join(); delete th; } ??? Добавлено Цитата progman @ servervisuald.exe!network::server::accept(int id, const boost::system::error_code & err) Line 39 C++ servervisuald.exe!network::server::handle_accept(network::server * srv, int id, const boost::system::error_code & err) Line 29 C++ твое? что там понаписано? Добавлено Складывается впечатление, что завершается accept с ошибкой и ты ее некорректно обрабатываешь. Хотя может я и ошибаюсь, так сложно сказать. |
Сообщ.
#29
,
|
|
|
вот полный код всей сетевой части:
void workerThread::workingThread( ) { mWorkerThread = this; try { server s( m_dbpool, io_service, m_serverport ); io_service.run(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } ::SetEvent( m_closeThreadEvent ); return; } server::server( dbPool& dbpool, boost::asio::io_service& io_service, short port) : m_acceptor( io_service, tcp::endpoint( tcp::v4( ), port ) ) , m_socket( io_service ) , m_dbpool( dbpool ) { m_acceptor.async_accept( m_socket, boost::bind( handle_accept, this, 0, _1 ) ); } server::~server() { } void server::handle_accept( server* srv, int id, const boost::system::error_code & err ) { srv->accept( id, err ); } void server::accept( int id, const boost::system::error_code & err ) { if (!err) { std::make_shared<connection>( m_dbpool, std::move( m_socket ) )->accept(); } m_acceptor.async_accept( m_socket, boost::bind( handle_accept, this, 0, _1 ) ); } const int CLIENT_TIMEOUT = 3600; connection::connection( dbPool& dbpool, tcp::socket socket ) : m_socket(std::move(socket)) , m_dbpool(dbpool) { m_pClient = NULL; m_inactivetime = 0; } connection::~connection() { //m_pClient will be destroy inside if (_S(net::ClientList) ) _S(net::ClientList)->remove(this); } void connection::update(float dt) { m_inactivetime += dt; if (m_inactivetime >= CLIENT_TIMEOUT) closeSocket(); } void connection::closeSocket() { m_socket.close(); } HRESULT connection::send( char* buffer, DWORD length ) { m_inactivetime = 0; char* sendbuffer = new char[length + header_length]; memcpy( &sendbuffer[ 0 ], &length, header_length); memcpy( &sendbuffer[ header_length ], buffer, length ); boost::asio::async_write( m_socket, boost::asio::buffer( sendbuffer, length + header_length ), std::bind( &connection::handle_write, shared_from_this(), sendbuffer, std::placeholders::_1, std::placeholders::_2 ) ); return S_OK; } HRESULT connection::sendPolicy() { const char mCrossDomainPolicy[] = "<?xml version=\"1.0\"?>\r\n<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\r\n<cross-domain-policy>\r\n<allow-access-from domain=\"*\" to-ports=\"1-31111\" />\r\n</cross-domain-policy>"; const int length = strlen(mCrossDomainPolicy); char* sendbuffer = new char[ length ]; memcpy( &sendbuffer[0], mCrossDomainPolicy, length ); boost::asio::async_write(m_socket, boost::asio::buffer( sendbuffer, length ), std::bind(&connection::handle_write, shared_from_this(), sendbuffer, std::placeholders::_1, std::placeholders::_2)); return S_OK; } void connection::handle_write(char* buffer, const boost::system::error_code& a_error, std::size_t a_size) { delete[] buffer; } void connection::accept() { m_inactivetime = 0; m_pClient = new Client( this, m_dbpool.getDataBase(dbPool::system), m_dbpool.getDataBase(dbPool::logi), m_dbpool.getDataBase(dbPool::tickets ) ); m_pClient->onConnect( m_socket.remote_endpoint().address().to_v4().to_ulong() ); _S(net::ClientList)->push( this ); do_read_header( ); } void connection::do_read_header() { m_inactivetime = 0; auto self( shared_from_this( ) ); m_socket.async_read_some(boost::asio::buffer(m_recvbuffer, header_length), [this, self](boost::system::error_code ec, std::size_t length) { if( !ec ) { int bodylength = ((int*)m_recvbuffer)[0]; if (bodylength > 0 && bodylength < max_length) { do_read_body( bodylength ); } else { const char mPolicyFileRequest[] = "<policy-file-request/>"; if ( 'lop<' == bodylength ) { do_read_body( static_cast< unsigned int > (strlen( mPolicyFileRequest ) - PROTOCOL_HEADER_SIZE) ); } else m_socket.close(); } } } ); } void connection::do_read_body( int datalength ) { m_inactivetime = 0; auto self( shared_from_this( ) ); m_socket.async_read_some(boost::asio::buffer( m_recvbuffer, datalength ), [this, self](boost::system::error_code ec, std::size_t length) { if( !ec ) { if ( 18 == length && checkPoliciFileRequest( m_recvbuffer ) ) { this->sendPolicy(); return; } else { HRESULT hr = m_pClient->onReceiveBlock((unsigned char*)m_recvbuffer, length); if (S_OK == hr) { do_read_header(); } if (S_DISCONNECT == hr) m_socket.close(); } } } ); } |
Сообщ.
#30
,
|
|
|
Цитата progman @ void server::accept( int id, const boost::system::error_code & err ) { if (!err) { std::make_shared<connection>( m_dbpool, std::move( m_socket ) )->accept(); } m_acceptor.async_accept( m_socket, boost::bind( handle_accept, this, 0, _1 ) ); } Скорее всего бага тут. Попробуй добавь для отладки проверку флага завершения: void server::accept( int id, const boost::system::error_code & err ) { if(TerminateFlag) return; if (!err) { std::make_shared<connection>( m_dbpool, std::move( m_socket ) )->accept(); } m_acceptor.async_accept( m_socket, boost::bind( handle_accept, this, 0, _1 ) ); } ... TerminateFlag = false; io_service.stop(); |
Сообщ.
#31
,
|
|
|
Цитата shm @ Цитата progman @ void server::accept( int id, const boost::system::error_code & err ) { if (!err) { std::make_shared<connection>( m_dbpool, std::move( m_socket ) )->accept(); } m_acceptor.async_accept( m_socket, boost::bind( handle_accept, this, 0, _1 ) ); } Скорее всего бага тут. Попробуй добавь для отладки проверку флага завершения: void server::accept( int id, const boost::system::error_code & err ) { if(TerminateFlag) return; if (!err) { std::make_shared<connection>( m_dbpool, std::move( m_socket ) )->accept(); } m_acceptor.async_accept( m_socket, boost::bind( handle_accept, this, 0, _1 ) ); } ... TerminateFlag = false; io_service.stop(); спасибо - флаг помог посылаю лучи респекта. |
Сообщ.
#32
,
|
|
|
progman, это не решение - это просто проверка, что ошибка тут. Проверяй причину ошибки, т. к. баг тут:
Цитата progman @ m_acceptor.async_accept( m_socket, boost::bind( handle_accept, this, 0, _1 ) ); нельзя так делать при остановке io_service. Можешь проверять код ошибки. Также у io_service есть метод bool stopped(). Добавлено И перепиши ожидание потоков. |
Сообщ.
#33
,
|
|
|
progman, ping. До ума-то будешь доводить? Складывается впечатление, что мне эта тема интереснее, чем тебе
|
Сообщ.
#34
,
|
|
|
shm
У него небось работы невпроворот... Труд, мир, май... |
Сообщ.
#35
,
|
|
|
Цитата shm @ progman, ping. До ума-то будешь доводить? Складывается впечатление, что мне эта тема интереснее, чем тебе костыли работают - глубоко копать правда нет времени от слова совсем ((( |
Сообщ.
#36
,
|
|
|
Цитата progman @ костыли работают - глубоко копать правда нет времени от слова совсем ((( Это неправильный подход. |