single_set
信号
信号是UNIX系统里常用的进程间异步通信方式
asio库提供类,利用异步IO的方式处理UNIX信号
类原型
class signal_set{
public:
explicit signal_set(io_service& io_service);
signal_set(io_service& io_serv, int number, ...);
void add(int signal_number);
void remove(int signal_number);
void clear();
void cancel();
void async_wait(SignalHandler handler);
};
构造函数中传入io_service
以提供异步操作
cancel()
取消所有handler的执行,实际上是向它们传入boost::asio::error::operation_aborted
错误,要求handler执行自己的cancel逻辑
async_wait()
异步添加信号处理函数,即handler,是非阻塞的,无需等待即可返回,handler形式如下:
void handler(const system::error_code& ec, int signal_number);
示例
io_service io;
signal_set sig(io, SIGINT, SIGUSR1);
// sig.add(SIGINT);
// sig.add(SIGUSR1);
auto handler1=[](const error_code& ec, int n){
if(ec){
cout<<ec.message()<<endl;
return;
}
if(n!=SIGINT){
return;
}
cout<<"handler1 recv="<<n<<endl;
cout<<"do something"<<endl;
};
typedef void(handler_type)(const error_code&,int);
function<handler_type> handler2=[](const error_type& ec, int n){
if(n!=SIGUSR1){
return;
}
cout<<"handler2 recv="<<n<<endl;
};
sig.async_wait(handler1);
sig.async_wait(handler2);
io.run(); // 启动事件循环,阻塞等待信号事件
cout<<"io stopped"<<endl;
执行命令kill -10 pid
将会发送信号SIGUSR1
,运行结果如下:
handler2 recv=10
io stopped
事件发生后,执行了对应的handler2,由于信号发生后注册的异步事件已经完成,所以io_service
会结束事件循环,退出run()
若想持续捕获信号,需要在信号处理完重新添加
function<handler_type> handler2=[](const error_type& ec, int n){
// ...
sig.async_wait(handler1);
sig.async_wait(handler2);
};
启用跟踪日志
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING
#include<boost/asio.hpp>
将输出重定向到日志文件
signal_set 2 > out.log
其他
超时处理
steady_timer t(io, 500ms)
t.async_wait(
[&](const error_code&){}
);
流处理
服务端
io_service io;
ip::tcp::endpoint ep(ip::tcp::v4(), 6688);
ip::tcp::acceptor acceptor(io, ep);
for(;;){
ip::tcp::iostream tcp_stream;
acceptor.accept(*tcp_stream.rdbuf());
tcp_stream<<"hello tcp stream";
}
客户端
for(int i=0; i<5; ++i){
ip::tcp::iostream tcp_stream("127.0.0.1", "6688")
string str;
getline(tcp_stream, str);
cout<< str <<endl;
}
UDP协议通信
UDP是无连接的,使用send_to()
和receive_from()
可以直接通过端点发送数据
服务端
int main(){
io_service io;
ip::udp::socket sock(io, ip::udp::endpoint(ip::udp::v4(),6699));
while(true){
char buf[1];
ip::udp::endpoint ep;
error_code ec;
// 阻塞等待远程连接,端点信息存在ip对象中
sock.receive_from(buffer(buf), ip, 0, ec);
if(ec && ec!=message_size){
throw system_error(ec);
cout<<"send to:"<<ep.address()<<endl;
sock.send_to(buffer("hello asio udp"), ep);
}
}
}
客户端
int main(){
io_service io;
ip::udp::endpoint send_ep(ip::address::from_string("127.0.0.1"),6699);
ip::udp::socket sock(io);
sock.open(ip::udp::v4());
char buf[1];
sock.send_to(buffer(buf), send_ep);
vector<char> v(100,0);
ip::udp::endpoint recv_ep;
sock.receive_from(buffer(v), recv_ep);
cout<<"recv from:"<<recv_ep.address()<<' ';
cout<<&v[0]<<endl;
}
UNIX描述符
除了网络通信,asio还支持UNIX Domain Socket和文件描述符操作
可以使用async_read_some()
/async_write_some()
等函数执行异步读写操作
io_service io;
typedefboost::asio::posix::stream_descriptor descriptor_type;
descriptor_type in(io, STDIN_FILENO);
vector<char> buf(30);
typedef void(handler_type)(const error_code&, std::size_t);
function<handler_type> handler=[&](const error_code& ec, std::size_t len){
if(ec){ return; }
if(len < buf.size()){
buf[len]= 0;
}
cout<<buf.data();
in.async_read_some(buffer(buf), handler);
};
in.async_read_some(buffer(buf), handler);
io.run();
UNIX文件描述符也可以使用协程
io_service io;
typedef boost::asio::posix::stream_descriptor descriptor_type;
descriptor_type in(io, STDIN_FILENO);
vector<char> buf[30];
// 产生协程
spawn(
io,
[&](yield_context yield){
while(true){
error_code ec;
auto len= in.async_read_some(buffer(buf), yield[ec])
if(ec){ return; }
if(len<buf.size()){
buf[len]= 0;
}
cout<<buf.data();
}
}
):
io.run();