Boost asio入門学習ノート


Timer 1:同期タイマの使用
#include 
#include "boost/asio.hpp"


int main()
{
	boost::asio::io_context io;
	boost::asio::steady_timer t(io, boost::asio::chrono::seconds(5));
	t.wait();
	std::cout << "Hello,world!" << std::endl;
	
	return 0;
}

同期とは、t.waitが下に実行されるまで5秒待たなければならないことを意味します. 
 
Timer 2:非同期タイマの使用
#include 
#include "boost/asio.hpp"


void print(const boost::system::error_code&)
{
	std::cout << "Hello world!" << std::endl;
}
int main()
{
	boost::asio::io_context io;
	boost::asio::steady_timer t(io, boost::asio::chrono::seconds(5));
	t.async_wait(&print);
	std::cout << "Hehe!" << std::endl;
	io.run();
	return 0;
}

非同期とは、上記のプログラムがt.async_には存在しないことを意味します.wait(&print)でブロックされ、タイマが5秒未満になるまでprintが呼び出されません.上記のプログラムの実行結果は、まずHeheを出力してからHello worldを出力します!
Timer 3:handleバインドパラメータ
#include 
#include "boost/asio.hpp"
#include "boost/bind.hpp"


void print(const boost::system::error_code&,boost::asio::steady_timer *t,int *count)
{
	if (*count < 5)
	{
		std::cout << *count << std::endl;
		++(*count);
		t->expires_at(t->expiry() + boost::asio::chrono::seconds(1));//        
		t->async_wait(boost::bind(print, boost::asio::placeholders::error, t, count));// print    ,       
	}
}
int main()
{
	boost::asio::io_context io;
	int count = 0;
	boost::asio::steady_timer t(io, boost::asio::chrono::seconds(1));
	t.async_wait(boost::bind(print,boost::asio::placeholders::error,&t,&count));
	io.run();
	std::cout << "Final count is " << count << std::endl;
	return 0;
}

Timer 4:handlerとしてメンバー関数を使用する
#include 
#include "boost/asio.hpp"
#include "boost/bind.hpp"


class printer
{
public:
	printer(boost::asio::io_context& io)
		:timer_(io, boost::asio::chrono::seconds(1)),
		count_(0)
	{
		timer_.async_wait(boost::bind(&printer::print, this));
	}
	~printer()
	{
		std::cout << "Final count is " << count_ << std::endl;
	}

	void print()
	{
		if (count_ < 5)
		{
			std::cout << count_ << std::endl;
			++count_;

			timer_.expires_at(timer_.expiry() + boost::asio::chrono::seconds(1));
			timer_.async_wait(boost::bind(&printer::print, this));
		}

	}
private:
	boost::asio::steady_timer timer_;
	int count_;
};
int main()
{
	boost::asio::io_context io;
	printer p(io);
	io.run();
	
	return 0;
}

以前のインスタンスで実装された機能と一致するのは、より巧みにすぎません.the asio library provides a guarantee that callback handlers will only be called from threads that are currently calling io_context::run(). Consequently, calling io_context::run() from only one thread ensures that callback handlers cannot run concurrently.すなわち,コールバック関数は1つのスレッドでしか呼び出せず,並列にはできない.
単一スレッドには次の制限があります.
  • handleが非常に時間がかかると、かわいそうな応答速度をもたらします.
  • では、マルチコアプロセッサの拡張最適化はできません.

  • Timer 5:マルチスレッドの同期Handlers
    #include 
    #include "boost/asio.hpp"
    #include "boost/thread/thread.hpp"
    #include "boost/bind.hpp"
    
    
    class printer
    {
    public:
    	printer(boost::asio::io_context& io)
    		:strand_(io),
    		timer1_(io, boost::asio::chrono::seconds(1)),
    		timer2_(io,boost::asio::chrono::seconds(1)),
    		count_(0)
    	{
    		timer1_.async_wait(boost::asio::bind_executor(strand_, boost::bind(&printer::print1, this))); //      strand    handler    
    		timer2_.async_wait(boost::asio::bind_executor(strand_, boost::bind(&printer::print2, this)));
    
    	}
    	~printer()
    	{
    		std::cout << "Final count is " << count_ << std::endl;
    	}
    
    	void print1()
    	{
    		if(count_ < 10)
    		{
    			std::cout << "Timer 1: " << count_ << std::endl;
    			++count_;
    
    			timer1_.expires_at(timer1_.expiry() + boost::asio::chrono::seconds(1));
    
    			timer1_.async_wait(boost::asio::bind_executor(strand_,
    				boost::bind(&printer::print1, this)));
    		}
    
    	}
    
    	void print2()
    	{
    		if (count_ < 10)
    		{
    			std::cout << "Timer 2: " << count_ << std::endl;
    			++count_;
    
    			timer2_.expires_at(timer2_.expiry() + boost::asio::chrono::seconds(1));
    
    			timer2_.async_wait(boost::asio::bind_executor(strand_,
    				boost::bind(&printer::print2, this)));
    		}
    	}
    
    private:
    	boost::asio::io_context::strand strand_;
    	boost::asio::steady_timer timer1_;
    	boost::asio::steady_timer timer2_;
    	int count_;
    };
    int main()
    {
    	boost::asio::io_context io;
    	printer p(io);
    	boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
    	io.run();
    	t.join();//         
    	
    	
    	return 0;
    }

    daytime 1:同期TCP daytimeクライアントを実現
    #include 
    #include
    #include "boost/asio.hpp"
    
    using  boost::asio::ip::tcp;
    
    int main(int argc,char * argv[])
    {
    	try
    	{
    		
    		boost::asio::io_context io_context; //All programs that use asio need to have at least one io_context object.
    		tcp::resolver resolver(io_context);
    
    		std::string host = "127.0.0.1";//specify the host
    										   //resolver    query  ,  query   a list of endpoints
    										   //host name,   IP  
    										   //the name of service,     ...
    		tcp::resolver::query query(tcp::v4(), host, "13");
    		//  tcp::resolver::query query(tcp::v4(),argv[1], "13");
    
    		
    		tcp::resolver::results_type endpoints = resolver.resolve(query);
    
    		tcp::socket socket(io_context);
    		boost::asio::connect(socket, endpoints);
    
    		for (;;)
    		{
    			boost::arraybuf;
    			boost::system::error_code error;
    
    			size_t len = socket.read_some(boost::asio::buffer(buf), error);
    
    			if (error == boost::asio::error::eof)
    			{
    				break;//    
    			}
    			else if (error)
    			{
    				throw boost::system::system_error(error);
    			}
    
    			std::cout.write(buf.data(), len);
    		}
    	}
    	catch (const std::exception& e)
    	{
    		std::cerr << e.what() << std::endl;
    	}
    	
    	return 0;
    }

    daytime 2:同期TCP daytimeサービスを実現
    #include 
    #include 
    #include 
    #include 
    
    using boost::asio::ip::tcp;
    
    std::string make_daytime_string()
    {
    	using namespace std;
    	time_t now = time(0);
    	return ctime(&now);
    }
    
    
    int main()
    {
    	try
    	{
    		boost::asio::io_context io_context;
    		tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 13));
    
    		for (;;)
    		{
    			tcp::socket socket(io_context);
    			acceptor.accept(socket);
    			std::string message = make_daytime_string();
    			boost::system::error_code igored_error;
    			boost::asio::write(socket, boost::asio::buffer(message), igored_error);
    		}
    	}
    	catch (const std::exception& e)
    	{
    		std::cerr << e.what() << std::endl;
    	}
    }

    daytime 3:非同期tcp daytimeのサービス側
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using boost::asio::ip::tcp;
    
    std::string make_daytime_string()
    {
    	using namespace std;
    	time_t now = time(0);
    	return ctime(&now);
    }
    
    class tcp_connection :public boost::enable_shared_from_this
    {
    public:
    	typedef boost::shared_ptr pointer;
    
    	static pointer create(boost::asio::io_context&io_context)
    	{
    		return pointer(new tcp_connection(io_context));
    	}
    
    	tcp::socket & socket()
    	{
    		return socket_;
    	}
    
    	void start()
    	{
    		message_ = make_daytime_string();
    		boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this(),
    			boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    	}
    
    private:
    
    	tcp_connection(boost::asio::io_context&io_context)
    		:socket_(io_context)
    	{
    
    	}
    	void handle_write(const boost::system::error_code, size_t)
    	{
    
    	}
    	tcp::socket socket_;
    	std::string message_;
    };
    
    
    class tcp_server
    {
    public:
    	tcp_server(boost::asio::io_context&io_context)
    		:acceptor_(io_context, tcp::endpoint(tcp::v4(), 13))
    	{
    		start_accept();
    	}
    
    private:
    
    	void start_accept()
    	{
    		tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_executor().context());
    		acceptor_.async_accept(new_connection->socket(), boost::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error));
    
    		//     ,    ,       ,  handle_accept
    	}
    
    	void handle_accept(tcp_connection::pointer new_connection,
    		const boost::system::error_code& error)
    	{
    		if (!error)
    		{
    			new_connection->start();
    		}
    
    		start_accept();
    	}
    	tcp::acceptor acceptor_;
    };
    
    int main()
    {
    	try
    	{
    		boost::asio::io_context io_context;
    		tcp_server server(io_context);
    		io_context.run();
    	}
    	catch (const std::exception& e)
    	{
    		std::cerr << e.what() << std::endl;
    	}
    }