boost::asio
asio 主要用于网络通信,封装了socket API, 包含了TCP, ICMP,UDP等协议,支持串口读写,定时器,SSL等。
asio 采用前摄器设计模式(Proactor) 实现了可移植的异步或同步IO操作,不要求多线程和锁定,避免了线程的竞争等问题。
- 定时器:deadline_timer:
定时器一旦创建就开始计时,可用wait()或async_wait()异步等待,终止时调用handler函数。
如果不指定终止时间,可用成员函数expires_at(), expires_from_now()指定绝对或相对的终止时间。
ip::tcp 类是asio 网络通信(TCP)主要的类,定义了数个typedef 类,包括:endpoint, socket, iostream, acceptor, resolver(解析器)等
- ip地址和端口
address 类用法示例:
ip::address addr;
addr = addr.from_string("127.0.0.1");
cout << addr.to_string() << endl;
加上端口:
ip::tcp::endpoint ep(addr, 6688) //创建断点对象,6688 为端口号
assert(ep.address()== addr);
assert(ep.port() == 6688);
ip::tcp 的内部类型socket, acceptor, 以及 resolver 是asio 库 TCP通信中最核心的一组类,封装了socket的链接,断开和数据首发功能,使用它们能比较方便编写socket的程序。
用法:成员函数connect() 连接到一个指定的通信端点,连接成功后用local_endpoint() 和 remote_endpoint() 获得连接两端的端点信息, read_some() 和 write_some() 阻塞读写数据,操作完成后用close()关闭socket.
acceptor 类对应accept() 等函数,用于服务器端; resolver 类对应 getaddrinfo() 等函数,用于客户端。
int main()
try{
cout << "server: " << endl;
io_service ios; //asio 必须的io_service 对象
ip::tcp::acceptor acceptor (ios, ip::tcp::endpoint(ip::tcp::v4(), 6688);
// 创建ipv4的对象,并打开6688端口
cout << acceptor.local_endpoint().address() << endl;
while(true)
{
ip::tcp::socket sock(ios); // 一个socket 对象
acceptor.accept (sock); // 等待连接
cout << "client";
cout << sock.remote_endpoint().address() << endl;
sock.write_some(buffer("hello asio")); // 发送数据
}
}
catch (std::exception& e)
{
cout << e.what() << endl;
}
异步socket 处理的例子:
class server
{
private:
io_service &ios;
ip::tcp::acceptor acceptor;
typedef shared_ptr<ip::tcp::socket> sock_ptr;
public:
server(io_service& io): ios(io), acceptor(ios,ip::tcp::endpoint(ip::tcp::v4(),6688)){ start(); }
}
然后用server()函数启动异步服务:
void start()
{
socket_ptr sock(new ip::tcp::socket(ios);
acceptor.async_accept(*sock, bind(&server::accept_handler, this, placeholder::error, sock));
}
shared_ptr 可以在程序的整个生命周期中存在。
TCP 发生连接时候,server::accept_handler()被调用,使用socket()发送数据
void accept_handler(const system::error_code& ec, sock_pt sock)
{
if(ec) { return;} //监测错误码
cout << "client:";
cout << sock->remote_endpoint().address() << endl; //连接的客户端信息
sock -> async_write_some(buffer("hello asio"), bind(&server::write_handler, this, placeholder::error));
start(); //启动异步接受连接
}
- 查询网络地址
resolver 使用内部类query 和 iterator 查询IP, 程序片段:
void resolv_connect(ip::tcp::socket &sock, const char* name, int port)
{
ip::tcp::resolver rlv(sock.get_io_service()); //resolver 对象
ip::tcp::resolver::query qry(name, lexical_cast<string>(port));
// lexical_cast 用于把端口号转为字符串
// 迭代端点,遍历query
ip::tcp::resolver::iterator iter = rlv.resolve(qry);
ip::tcp::resolver::iterator end;
system::error_code ec = error::host_not_found;
for( ; ec && iter!= end; ++iter)
{
sock.close();
sock.connect(*iter,ec); //连接
}
if (ec) { throw syste::system_error(ec); }
cout << "connect success." <<endl;
}
thread 库和asio 库均可以用于并发编程,但是解决问题的途径不同,thread 使用线程机制,无需OS内核的干预,只要线程同步做好。而asio 使用异步时间处理机制,与OS的内核密切相关,需要对OS的底层机制有一定了解,比线程更难调试,而把异步处理交给OS,从而获得更高运行性能。(EOS里面那么多asio,哎,除了提高性能的原因,是否也有故意提高调试门槛的味道?)
网友评论