C++大法:举世闻名之BOOST大法精华浅析(十)asio的网络编程基础(小白piao分享)

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白piao

创作不易,支持一下!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值