コールバックオブジェクトは、io_serviceクラスのrun()メソッドの実行後にのみ呼び出されることに注意してください。そうしないと、システムが非同期操作を完了した場合でも、タスクアクションは発生しません。
さて、それだけです。これが私が持ってきた非同期TCPHelloworldサーバーです。
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/smart_ptr.hpp>
using namespace boost::asio;
using boost::system::error_code;
using ip::tcp;
struct CHelloWorld_Service{
CHelloWorld_Service(io_service &iosev)
:m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 1000))
{
}
void start()
{
// 开始等待连接(非阻塞)
boost::shared_ptr<tcp::socket> psocket(new tcp::socket(m_iosev));
// 触发的事件只有error_code参数,所以用boost::bind把socket绑定进去
m_acceptor.async_accept(*psocket,
boost::bind(&CHelloWorld_Service::accept_handler,this, psocket, _1)
);
}
// 有客户端连接时accept_handler触发
void accept_handler(boost::shared_ptr<tcp::socket> psocket, error_code ec)
{
if(ec) return;
// 继续等待连接
start();
// 显示远程IP
std::cout << psocket->remote_endpoint().address() << std::endl;
// 发送信息(非阻塞)
boost::shared_ptr<std::string> pstr(new std::string("hello async world!"));
psocket->async_write_some(buffer(*pstr),
boost::bind(&CHelloWorld_Service::write_handler, this, pstr, _1, _2)
);
}
// 异步写操作完成后write_handler触发
void write_handler(boost::shared_ptr<std::string> pstr,
error_code ec, size_t bytes_transferred)
{
if(ec)
std::cout<< "发送失败!" << std::endl;
else
std::cout<< *pstr << " 已发送" << std::endl;
}
private:
io_service &m_iosev;
ip::tcp::acceptor m_acceptor;
};
int main(int argc, char* argv[])
{
io_service iosev;
CHelloWorld_Service sev(iosev);
// 开始等待连接
sev.start();
iosev.run();
return 0;
}
この例では、最初にsev.start()を呼び出して、クライアント接続の受け入れを開始します。async_acceptは呼び出しの直後に戻るため、start()メソッドはすぐに完了します。sev.start()が即座に戻ると、iosev.run()の実行が開始されます。iosev.run()メソッドは、非同期コールバックイベントの配布を担当するループです。すべての非同期操作が完了した場合にのみ、戻ります。
ここで問題があります。これは、start()メソッドのm_acceptor.async_accept操作で使用されるtcp :: socketオブジェクトが、非同期操作全体で有効なままであることを確認することです(そうでない場合、システムは下部の非同期操作の半分になります)システムの、そして突然tcp :: socketがなくなったのに気づきました。人々はそれを開きます-_- !!!)、そしてtcp :: socketオブジェクトはクライアントが接続された後もまだ役に立ちます。ここでの解決策は、カウント付きのスマートポインターboost :: shared_ptr <tcp :: socket>を使用し、このポインターをパラメーターとしてコールバック関数にバインドすることです。
クライアント接続が確立されると、start()で指定したコールバック関数accept_handlerが呼び出され、最初にstart()を呼び出して他のクライアントの接続を非同期で待機し続け、次にバインドされたtcp :: socketオブジェクトを使用して通信します。現在のクライアントで。
非同期メソッド(async_write_some)もデータの送信に使用され、非同期送信期間全体でのバッファーの有効性も保証する必要があるため、boost :: bindもboost :: shared_ptr <std :: string>にバインドされます。