asio
基于操作系统移植性好的异步机制框架,该框架弹性强,目前主要用于网络通信方面,提供了很多现代C++的网络编程接口,支持TCP\ICMP\UDP等协议,asio并不局限于网络编程,它还支持串口读写、定时器、SSL等。
其使用时并不需要编译,但是依赖一些基本库诸如:boost.system和boost.datetime库,用来提供系统错误和时间的支持。其他可选库有:regex、thread和serialization,如果支持SSL还要安装openSSL。
需要包含的头文件形式框架:
#ifdef _MSC_VER
#define _WIN32_WINNT 0X0501
#endif
#define BOOST_REGEX_NO_LIB
#define BOOST_DATE_TIME_SOURCE
#define BOOST_SYSTEM_NO_LIB
#include <boost/asio.hpp>
using namespace boost::asio
在异步模式下,程序除了要发起IO操作以外, 还要定义一个用于回调的完成处理函数, io_service同样把IO操作交给了系统执行,但是它不同步等待。而是立即返回。调用io_service的run()成员函数可以等待异步操作完成,当异步操作完成时,io_service从异步操作中取得执行结果,调用完成处理函数。
asio不使用系统线程的定义,而是**自己定义strand,它保证了多个线程安全地执行且并不适用互斥量。io_service::strand::wrap()**函数可以包装一个函数在strand中执行。
IO操作会经常使用到缓冲区,asio库专门提供了两种类mutable_buffer和const_buffer类来封装这两个概念,可以安全地使用于异步的读写操作中。使用buffer()函数能够自由包装常用的c++标准容器例如数组、vector、array、string等。用**read()和write()**函数来读取缓冲区。
8.4.1 网络通信技术
asio支持TCP\UDP\ICMP通信协议,在命名空间boost::asio::ip里边提供了大量的网络通信方面的函数和类,很好地封装了原始的Socket API,展示给用户一个方便易用且健壮的asio网络通信库,接下来讨论最主要的是最广泛使用的TCP协议。
ip::tcp类是asio网络通信最主要的一个类,它本身没有什么功能,主要都是一些typedef,更类似于一个命名空间,包括端点类endpoint、套接字类socket、流类iostream、以及接收器acceptor、解析器resolver等等。
ip::tcp类如下:
class tcp
{
public:
/// The type of a TCP endpoint.
typedef basic_endpoint<tcp> endpoint;
/// Construct to represent the IPv4 TCP protocol.
static tcp v4() BOOST_ASIO_NOEXCEPT
{
return tcp(BOOST_ASIO_OS_DEF(AF_INET));
}
/// Construct to represent the IPv6 TCP protocol.
static tcp v6() BOOST_ASIO_NOEXCEPT
{
return tcp(BOOST_ASIO_OS_DEF(AF_INET6));
}
/// Obtain an identifier for the type of the protocol.
int type() const BOOST_ASIO_NOEXCEPT
{
return BOOST_ASIO_OS_DEF(SOCK_STREAM);
}
/// Obtain an identifier for the protocol.
int protocol() const BOOST_ASIO_NOEXCEPT
{
return BOOST_ASIO_OS_DEF(IPPROTO_TCP);
}
/// Obtain an identifier for the protocol family.
int family() const BOOST_ASIO_NOEXCEPT
{
return family_;
}
/// The TCP socket type.
typedef basic_stream_socket<tcp> socket;
/// The TCP acceptor type.
typedef basic_socket_acceptor<tcp> acceptor;
/// The TCP resolver type.
typedef basic_resolver<tcp> resolver;
#if !defined(BOOST_ASIO_NO_IOSTREAM)
/// The TCP iostream type.
typedef basic_socket_iostream<tcp> iostream;
#endif
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined no_delay;
#else
typedef boost::asio::detail::socket_option::boolean<
BOOST_ASIO_OS_DEF(IPPROTO_TCP), BOOST_ASIO_OS_DEF(TCP_NODELAY)> no_delay;
#endif
/// Compare two protocols for equality.
friend bool operator==(const tcp& p1, const tcp& p2)
{
return p1.family_ == p2.family_;
}
/// Compare two protocols for inequality.
friend bool operator!=(const tcp& p1, const tcp& p2)
{
return p1.family_ != p2.family_;
}
private:
// Construct with a specific family.
explicit tcp(int protocol_family) BOOST_ASIO_NOEXCEPT
: family_(protocol_family)
{
}
int family_;
};
} // namespace ip
} // namespace asio
} // namespace boost
8.4.2 ip地址和端点
ip地址独立于TCP\UDP等通信协议,asio库使用类ip::address来表示IP地址,可以同时支持ipv4和ipv6两种地址,其类如下:
class address
{
public:
/// Default constructor.
BOOST_ASIO_DECL address() BOOST_ASIO_NOEXCEPT;
/// Construct an address from an IPv4 address.
BOOST_ASIO_DECL address(
const boost::asio::ip::address_v4& ipv4_address) BOOST_ASIO_NOEXCEPT;
/// Construct an address from an IPv6 address.
BOOST_ASIO_DECL address(
const boost::asio::ip::address_v6& ipv6_address) BOOST_ASIO_NOEXCEPT;
/// Copy constructor.
BOOST_ASIO_DECL address(const address& other) BOOST_ASIO_NOEXCEPT;
#if defined(BOOST_ASIO_HAS_MOVE)
/// Move constructor.
BOOST_ASIO_DECL address(address&& other) BOOST_ASIO_NOEXCEPT;
#endif // defined(BOOST_ASIO_HAS_MOVE)
/// Assign from another address.
BOOST_ASIO_DECL address& operator=(const address& other) BOOST_ASIO_NOEXCEPT;
#if defined(BOOST_ASIO_HAS_MOVE)
/// Move-assign from another address.
BOOST_ASIO_DECL address& operator=(address&& other) BOOST_ASIO_NOEXCEPT;
#endif // defined(BOOST_ASIO_HAS_MOVE)
/// Assign from an IPv4 address.
BOOST_ASIO_DECL address& operator=(
const boost::asio::ip::address_v4& ipv4_address) BOOST_ASIO_NOEXCEPT;
/// Assign from an IPv6 address.
BOOST_ASIO_DECL address& operator=(
const boost::asio::ip::address_v6& ipv6_address) BOOST_ASIO_NOEXCEPT;
/// Get whether the address is an IP version 4 address.
bool is_v4() const BOOST_ASIO_NOEXCEPT
{
return type_ == ipv4;
}
/// Get whether the address is an IP version 6 address.
bool is_v6() const BOOST_ASIO_NOEXCEPT
{
return type_ == ipv6;
}
/// Get the address as an IP version 4 address.
BOOST_ASIO_DECL boost::asio::ip::address_v4 to_v4() const;
/// Get the address as an IP version 6 address.
BOOST_ASIO_DECL boost::asio::ip::address_v6 to_v6() const;
/// Get the address as a string.
BOOST_ASIO_DECL std::string to_string() const;
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use other overload.) Get the address as a string.
BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const;
/// (Deprecated: Use make_address().) Create an address from an IPv4 address
/// string in dotted decimal form, or from an IPv6 address in hexadecimal
/// notation.
static address from_string(const char* str);
/// (Deprecated: Use make_address().) Create an address from an IPv4 address
/// string in dotted decimal form, or from an IPv6 address in hexadecimal
/// notation.
static address from_string(const char* str, boost::system::error_code& ec);
/// (Deprecated: Use make_address().) Create an address from an IPv4 address
/// string in dotted decimal form, or from an IPv6 address in hexadecimal
/// notation.
static address from_string(const std::string& str);
/// (Deprecated: Use make_address().) Create an address from an IPv4 address
/// string in dotted decimal form, or from an IPv6 address in hexadecimal
/// notation.
static address from_string(
const std::string& str, boost::system::error_code& ec);
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Determine whether the address is a loopback address.
BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT;
/// Determine whether the address is unspecified.
BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT;
/// Determine whether the address is a multicast address.
BOOST_ASIO_DECL bool is_multicast() const BOOST_ASIO_NOEXCEPT;
/// Compare two addresses for equality.
BOOST_ASIO_DECL friend bool operator==(const address& a1,
const address& a2) BOOST_ASIO_NOEXCEPT;
/// Compare two addresses for inequality.
friend bool operator!=(const address& a1,
const address& a2) BOOST_ASIO_NOEXCEPT
{
return !(a1 == a2);
}
/// Compare addresses for ordering.
BOOST_ASIO_DECL friend bool operator<(const address& a1,
const address& a2) BOOST_ASIO_NOEXCEPT;
/// Compare addresses for ordering.
friend bool operator>(const address& a1,
const address& a2) BOOST_ASIO_NOEXCEPT
{
return a2 < a1;
}
/// Compare addresses for ordering.
friend bool operator<=(const address& a1,
const address& a2) BOOST_ASIO_NOEXCEPT
{
return !(a2 < a1);
}
/// Compare addresses for ordering.
friend bool operator>=(const address& a1,
const address& a2) BOOST_ASIO_NOEXCEPT
{
return !(a1 < a2);
}
private:
// The type of the address.
enum { ipv4, ipv6 } type_;
// The underlying IPv4 address.
boost::asio::ip::address_v4 ipv4_address_;
// The underlying IPv6 address.
boost::asio::ip::address_v6 ipv6_address_;
};
例子:
#include <iostream>
#include <boost/asio.hpp>
using namespace boost::asio;
using namespace std;
int main()
{
ip::address addr;
addr = addr.from_string("127.0.0.1");//设置ip地址
ip::tcp::endpoint ep(addr,8888);//绑定连接点
assert(ep.address()==addr);
assert(ep.port()==8888);
return 0;
}
8.4.3 同步socket处理
ip::tcp类内部类socket,acceptor,和resolver是asio库TCP通信中最核心的一组类,他们封装了socket的连接、断开和数据收发功能。
socket类是TCP类的基本类,调用成员函数connect()可以连接到一个指定的通信端点,连接成功后用local_endpoint()和remote_endpoint()获得两个端点的端点信息,用read_some()和write_some()阻塞读写数据,当操作完成后使用close()关闭socket套接字,如果不关闭套接字,最后socket对象析构时也会自动调用close()关闭。
acceptor类对应socket API的getaddrinfo()系列函数,用于客户端解析网址获得可用的IP地址,解析得到的ip地址可以用来socket对象的连接。
接下来用上述提及的类和函数实现一个同步通信的服务器和客户端。
#ifdef _MSVC_VER
#define _WIN32_WINNT 0X0501
#endif
#define BOOST_REGEX_NO_LIB
#define BOOST_DATE_TIME_SOURCE
#define BOOST_SYSTEM_NO_LIB
#include <iostream>
#include <boost/asio.hpp>
using namespace boost::asio;
using namespace std;
int main()
{
//1、ip:
// ip::address addr;
// addr = addr.from_string("127.0.0.1");//设置ip地址
// ip::tcp::endpoint ep(addr,8888);//绑定连接点
// assert(ep.address()==addr);
// assert(ep.port()==8888);
//2、同步服务器:
try {
cout<<"server start"<<endl;
io_service ios;
//创建接受者对象,绑定ip地址和端口号
ip::tcp::acceptor acceptor(ios,ip::tcp::endpoint(ip::tcp::v4(),8888));
cout << acceptor.local_endpoint().address()<<endl;//获取服务器ip地址
while(true){
ip::tcp::socket sock(ios);
acceptor.accept(sock);
cout<<"client:"<<sock.remote_endpoint().address()<<endl;//获取接入的客户端的ip
sock.write_some(buffer("hello asio"));
}
} catch (std::exception &e) {
cout<<e.what()<<endl;
}
return 0;
}
#ifdef _MSVC_VER
#define _WIN32_WINNT 0X0501
#endif
#define BOOST_REGEX_NO_LIB
#define BOOST_DATE_TIME_SOURCE
#define BOOST_SYSTEM_NO_LIB
#include <iostream>
#include <boost/asio.hpp>
#include <vector>
#include <boost/ref.hpp>
using namespace boost::asio;
using namespace std;
void client(io_service& ios)
{
try {
cout<<"client start"<<endl;
ip::tcp::socket sock(ios);
ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"),8888);
sock.connect(ep);
vector<char> str(100,0);
sock.read_some(buffer(str));
cout<<"recive from:"<<sock.remote_endpoint().address();
cout<<&str[0]<<endl;
} catch (std::exception &e) {
cout<<e.what()<<endl;
}
}
int main()
{
//1、同步通信客户端
io_service ios;
deadline_timer dt(ios,boost::posix_time::seconds(5));
dt.async_wait(bind(client,ref(ios)));
ios.run();//启动ios事件循环,等待计时器异步调用结束
return 0;
}