C++2.0

Boost(二)

2018-10-24  本文已影响6人  芒鞋儿
boost::asio

asio 主要用于网络通信,封装了socket API, 包含了TCP, ICMP,UDP等协议,支持串口读写,定时器,SSL等。
asio 采用前摄器设计模式(Proactor) 实现了可移植的异步或同步IO操作,不要求多线程和锁定,避免了线程的竞争等问题。

ip::tcp 类是asio 网络通信(TCP)主要的类,定义了数个typedef 类,包括:endpoint, socket, iostream, acceptor, resolver(解析器)等

  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();  //启动异步接受连接
}
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,哎,除了提高性能的原因,是否也有故意提高调试门槛的味道?)




上一篇下一篇

猜你喜欢

热点阅读