Boost.Asio 筆記

《Boost.Asio C++ Network Programming》

libtorrent使用了Boost.Asio

支持
network
com serial ports
files

實現同步/異步輸入輸出
read(stream, buffer)
async_read(stream, buffer)
write(stream, buffer)
async_write(stream, buffer)

TCP UDP IMCP
可以根據自己的需要擴展使其支持自己的協議

如果使用同步模式,因爲是阻塞模式,所以服務器客戶端往往使用多線程

編程前儘早決定使用同步還是異步模式
異步模式調試更困難

  • 同步多線程
  • 異步單線程

例:同步客戶端

using boost::asio;
io_service service;
ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1", 2001);
ip::tcp::socket(service);
sock.connect(ep);

Boost.Asio uses io_service to talk to the operating system’s input/output services.

同步服務器

using boost::asio;
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
io_service service;
ip::tcp::endpoint ep(ip::tcp::v4(), 2001)); // listen on 2001
ip::tcp::acceptor acc(service, ep);
while (true)
{
    socket_ptr sock(new ip::tcp::socket(service));
    acc.accept(*sockt);
    boost::thread(boost::bind(client_session, sock);
}
void client_session(socket_ptr sock)
{
    while (true)
    {
        char data[512];
        size_t len = sock->read_some(buffer(data));
        if (len > 0)
            write(*sock, buffer("ok", 2));
    }
}

異步客戶端

using boost::asio;
io_service service;
ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1", 2001);
ip::tcp::socket sock(service);
sock.async_connect(ep, connect_handler);
service.run();

void connect_handler(const boost::system::error_code& ec)
{
    // here we known we connected successfully
    // if ec indicates success
}

// service.run() 直到所有異步操作完成才退出

異步服務器

using boost::asio;
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
io_service service;
ip::tcp::endpoint ep(ip::tcp::v4(), 2001);
ip::tcp::acceptor acc(service, ep);
socket_ptr sock(new ip::tcp::socket(service));
start_accept(sock);
service.run();

void start_accept(socket_ptr sock)
{
    acc.async_accept(*sock, boost::bind(handle_accept, sock, _1));
}

void handle_accept(socket_ptr sock, const boost::system::error_code& err)
{
    if (err) 
        return;

    // at this point, you can read/write to the socket

    socket_ptr sock(new ip::tcp::socket(service));
    start_accept(sock);
}

異常處理

using boost::asio;
ip::tcp::endpoint ep;
ip::tcp::socket sock(service);
// 拋出異常 boost::system::system_error
try
{
    sock.connect(ep);
} catch (boost::system::system_error& e)
{ std::cout << e.code() << std::endl; }
boost::system::error_code err;
// 返回錯誤代碼
sock.connect(ep, err);
if (err)
    std::cout << err << std::endl;

異步模式始終返回錯誤代碼,異步函數不會拋出異常。

char data[512];
boost::system::error_code error;
size_t length = sock.read_some(buffer(data), error);
if (error == error::eof)
    return; // Connection closed
boost/asio/error.hpp

io_service 是線程安全的。
多個線程可以調用io_service::run()
回調函數會在任意一個調用run()的線程中執行。

socket類不是線程安全的
應該避免一個線程讀另一個線程寫同一個socket

utility 用在多個線程中是沒有意義的,所以不是線程安全的。
Most of them are meant to just be used for a short time, then
go out of scope.

除了網絡之外:
信號

void signal_handler(const boost::system::error_code & err, int signal)
{
// log this, and terminate application
}
boost::asio::signal_set sig(service, SIGINT, SIGTERM);
sig.async_wait(signal_handler);

串口

Using Boost.Asio, you can easily connect to a serial port. The port name is COM7 on
Windows, or /dev/ttyS0 on POSIX platforms:
io_service service;
serial_port sp(service, "COM7");
serial_port::baud_rate rate(9600);
sp.set_option(rate);

其他詳見Boost.Asio C++ Network Programming.pdf 14頁

計時器

sock.async_read_some(buffer(data, 512));
deadline_timer t(service, boost::posix_time::milliseconds(100));
t.async_wait(&deadline_handler);
service.run();

同步計時器和sleep等價

boost::this_thread::sleep(500);
// -or-
deadline_timer t(service, boost::posix_time::milliseconds(500));
t.wait();

以下代碼沒有意義,多個service實例運行在同一個線程中
因爲service_[1].run()需要等待service_[0].run()完成。

for ( int i = 0; i < 2; ++i)
    service_[i].run();

1.
線程1 s.run() 所有回調函數的調用在該線程中是同步的
2.
線程1 s.run() 所有回調函數會被分配到多個線程異步執行
線程2 s.run()
3.
線程1 s1.run()
線程2 s2.run()

使run()函數始終運行的方法

  1. 在回調函數中執行新的異步操作
  2. The other way is to simulate some work for it,
    by using the following code snippet:
    typedef boost::shared_ptr work_ptr;
    work_ptr dummy_work(new io_service::work(service_));
    The preceding code will make sure that service_.run()never stops unless you
    either use service_.stop() or dummy_work.reset(0); // destroy dummy_work.
// service.post()

io_service::strand strand_one(service);
service.post(strand_one.wrap(boost::bind(func, i)));

service.dispatch()
如果當前進程調用了run(),dispatch()將等待,直達任務被執行完畢。
post()是立即返回

boost::function

boost::thread_group threads;
threads.create_thread(func1);
threads.create_thread(func2);
threads.join_all();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章