《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()函數始終運行的方法
- 在回調函數中執行新的異步操作
- 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();