3

Boost の SSL ASIO ライブラリを使用するマルチスレッド コードがあります。コードはマルチスレッドですが、各 SSL 接続に関連付けられたミューテックスがあり、async_*関数の呼び出しはミューテックスを保持して行われます。

自分のコードが停止してしまうことがあります。スレッドが詰まっています。糸が絡んでいbio_writeます。スタック トレースは次のようになります。

#0  0x00000000010a974f in bio_write ()   

#1  0x00000000010a3529 in BIO_write ()

#2  0x000000000105fe72 in ssl3_write_pending ()

#3  0x0000000001060b02 in ssl3_write_bytes ()

#4  0x0000000000cce43a in boost::asio::ssl::detail::engine::do_write
(this=0x1e618a0, data=0x234c7b0, length=189) at
/usr/include/boost/asio/ssl/detail/impl/engine.ipp:294

#5  0x0000000000cce109 in boost::asio::ssl::detail::engine::perform(this=0x1e618a0, op=(int
(boost::asio::ssl::detail::engine::*)(boost::asio::ssl::detail::engine *
const, void *, std::size_t)) 0xcce3fc<boost::asio::ssl::detail::engine::do_write(void*, unsigned long)>,
data=0x234c7b0, length=189, ec=..., bytes_transferred=0x7fff8ad74d48) at
/usr/include/boost/asio/ssl/detail/impl/engine.ipp:219

#6  0x0000000000ccdd23 in boost::asio::ssl::detail::engine::write
(this=0x1e618a0, data=..., ec=..., bytes_transferred=@0x7fff8ad74d48: 0) at
/usr/include/boost/asio/ssl/detail/impl/engine.ipp:137

#7  0x0000000000dac504 in boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>::operator()
(this=0x7fff8ad74d20, eng=..., ec=..., bytes_transferred=@0x7fff8ad74d48: 0)
at /usr/include/boost/asio/ssl/detail/write_op.hpp:51

#8  0x0000000000da9d8a in boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> >,
boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>,
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1>
(*)(), boost::arg<2> (*)()> > > >::operator() (this=0x7fff8ad74d10, ec=..., 
bytes_transferred=0, start=1) at /usr/include/boost/asio/ssl/detail/io.hpp:136

#9  0x0000000000da7f42 in boost::asio::ssl::detail::async_io<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> >,
boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>,
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1> (*)(),
boost::arg<2> (*)()> > > > (next_layer=..., core=..., op=...,
handler=...) at /usr/include/boost/asio/ssl/detail/io.hpp:322

#10 0x0000000000da634d in
boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> >
>::async_write_some<boost::asio::mutable_buffers_1,
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1>
(*)(), boost::arg<2> (*)()> > > > (this=0x1e61880, buffers=..., handler=...)
at /usr/include/boost/asio/ssl/stream.hpp:502

#11 0x0000000000da3032 in
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1>
(*)(), boost::arg<2> (*)()> > >::operator() (this=0x7fff8ad74f00, ec=...,   
bytes_transferred=0, start=1) at /usr/include/boost/asio/impl/write.hpp:250 

#12 0x0000000000d9ffbb in
boost::asio::async_write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::_bi::bind_t<void,
boost::_mfi::mf2<void, Peer, boost::system::error_code const&, unsigned
long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >,  
boost::arg<1> (*)(), boost::arg<2> (*)()> > > (s=..., buffers=...,     
handler=...) at /usr/include/boost/asio/impl/write.hpp:585

何か案は?

4

2 に答える 2

5

これは、マルチスレッドの問題の結果です。

ほとんどの Boost.Asio オブジェクトでは、オブジェクトに対して複数の非同期操作を保留しても安全です。オブジェクトの同時呼び出しは安全でないと指定されているだけです。ただし、通常、 などの一部のタイプでは問題になりませんip::tcp::socket。ただし、次のことをssl::stream強調します。

また、アプリケーションは、すべての非同期操作が同じ暗黙的または明示的なストランド内で実行されるようにする必要があります。

あなたの場合、解決策はwrap()、同じストランドによる各構成操作の完了ハンドラーに対するものです。これにより、すべての中間操作がストランド内で呼び出されます。スレッドの安全性とストランドのニュアンスの詳細については、この回答を読んでください。

于 2013-03-12T16:48:41.073 に答える
0

コードを提供していただけると助かります。スタックトレースだけから分析するのはちょっと難しいです。何らかの理由でコードを提供できない場合は、次のアイデアを参考にしてください。

bio_write は、ソケットにデータを書き込むために呼び出されるオープン SSL メソッドです。これを直接呼び出そうとすると、いくつかの問題が発生する可能性があります。 他の誰かが数ヶ月前にそれを使おうとして助けを求めましたが、答えはありませんでした.

ASIO と SSL も使用しています。私のコードでは、1 つのスレッドを使用してメッセージをソケットに書き込み、別のスレッドを使用してソケットからのメッセージの読み取りを処理します。私のクライアントは複数のサーバーと通信していますが、すべてのサーバーですべてのソケット I/O を処理するために合計 2 つのスレッドがあります。ソケットに書き出すためのコードは次のとおりです。これまでのところ、Windows で問題はありません。

void SSLSocket::SendWorkerThread(SSLSocket* psSLS)
{
   // This thread method that gets called to process the messages to be sent to the server.
   //
   // Since this has to be a static method, call a method on the class to handle server requests.
   psSLS->ProcessSendRequests();
}

void SSLSocket::ProcessSendRequests()
{
   // This method handles sending msgs to the server.
   //
   std::stringstream ss;
   DWORD WaitResult;
   Log.LogString("SSLSocket::ProcessSendRequests: Worker thread " + Logger::NumberToString(boost::this_thread::get_id()) + " started.\n", LogInfo);
   // Loop until the user quits, or an error of some sort is thrown.
   try
   {
      do
      {
         // If there are one or more msgs that need to be sent to a server, then send them out.
         if (SendMsgQ.Count() > 0)
         {
            Message* pMsg = SendMsgQ.Front();
            SSLSocket* pSSL = pMsg->pSSL;
            SendMsgQ.Pop();
            const Byte* pBuf = pMsg->pBuf;
            const int BytesInMsg = pMsg->BytesInMsg;
            boost::system::error_code Error;
            {
               Locking CodeLock(SocketLock); // Single thread the code.
               // unsigned int BytesTransferred = boost::asio::write(*pSSL->pSocket, boost::asio::buffer(pBuf, BytesInMsg), Error);
               boost::asio::async_write(*pSSL->pSocket, boost::asio::buffer(pBuf, BytesInMsg), boost::bind(&SSLSocket::HandleWrite, this,
                  boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
            }
            ss << "SSLSocket::ProcessSendRequests: # bytes sent = " << BytesInMsg << "\n";
            Log.LogString(ss.str(), LogDebug2);
            Log.LogBuf(pBuf, BytesInMsg, DisplayInHex, LogDebug3);
         }
         else
         {
            // Nothing to send, so go into a wait state.
            WaitResult = WaitForSingleObject(hEvent, INFINITE);
            if (WaitResult != 0L)
            {
               Log.LogString("SSLSocket::ProcessSendRequests: WaitForSingleObject event error.  Code = " + Logger::NumberToString(GetLastError()) + ". \n", LogError);
            }
         }
      } while (ReqAlive);
      Log.LogString("SSLSocket::ProcessSendRequests: Worker thread " + Logger::NumberToString(boost::this_thread::get_id()) + " done.\n", LogInfo);
   }
   catch (std::exception& e)
   {
      stringstream ss;
      ss << "SSLSocket::ProcessSendRequests: threw an error - " << e.what() << ".\n";
      Log.LogString(ss.str(), LogError);
      Stop();
   }
}

ソケットへの書き込みを試みる前に、ハンドシェークを完了する必要があることに注意してください。難しい方法でそれを学びました。

これで解決しない場合は、書き込もうとしているバイト数を出力してみてください。大量のバイトを書き出そうとしている場合は、調べる価値があるかもしれません。ASIO は大きな数で問題ないかもしれませんが、SSL はそうではないかもしれません。プログラムをデバッグ状態にして、書き込みステートメントの呼び出しにブレークポイントを設定することもできます。バッファ構造を調べて、io_service オブジェクトや socket オブジェクトなどの他のオブジェクトと同様に、何かが踏まれていないか、意図せずに破壊されていないかを確認してください。

OpenSSL Web サイトが最も安定したバージョンであると主張しているため、SSL ライブラリのバージョン c を使用しています。そのため、それよりも新しいバージョンを使用していて、他のすべてが失敗した場合は、代わりにバージョン c を使用してみてください。

于 2013-03-12T04:17:09.740 に答える