zoukankan      html  css  js  c++  java
  • Asio实现TCP套接字通信

    1. boost::asio介绍:
           (1)Boost.Asio是一个跨平台的、主要用于网络和其他一些底层输入/输出编程的C++库。Boost.Asio在网络通信抽象了IO概念,可以用它进行同步或者异步的IO网络编程。Boost.Asio可以在大多数操作系统上使用,能同时支持数千个并发的连接。
           (2)Asio可以进行异步网络编程,其采用前摄器模式实现异步IO,不需要多线程和锁机制(避免了竞争和死锁)。它内部封装了select、kqueue、poll/epoll、overlappedIO等机制。
           (3)io_service是asio库的异步处理处理机制(类似epoll),它负责与操作系统交互,通过调用其run()函数来等待所有的异步操作完成,并为每一个异步操作调用其handler回调函数。它必须先初始化,
           (4)Asio工作在同步模式:程序发起IO操作请求,随即向IO_service提交请求,由IO_service将请求转交给内核,之后阻塞等待IO操作完成。IO操作完成后由内核通知IO_service,IO_service将结果交给程序。
                  Asio工作在异步模式:程序发起IO操作请求,随即向IO_service提交请求,由IO_service将请求转发给内核,同时注册handler回调函数,之后立即返回。IO_service的run函数将等待IO操作完成,完成后从内核取回结果并调用handler函数。    
     
    2. boost::asio有关网络通信的API
    (1)IP地址类:
    • p::address(v4_or_v6_address):把一个ipv4或者ipv6地址转换成ip::address
    • ip::address::from_string(str):根据一个IPv4地址(.隔开)或者一个IPv6地址(十六进制)创建一个地址。
    • ip::address::to_string() :返回这个地址的字符串。
    (2)端点类:
    • endpoint(protocol, port):创建可以接受新连接的Server端点。
    • endpoint(addr, port):创建一个连接到某个地址和端口的Client端点。
    (3)套接字类:
      socket类可以创建一个相应的socket,而且总是在构造的时候传入io_service实例:
    io_service ios;
    ip::tcp::socket sock(ios);
    (4)socket类的常用方法:
    TCP连接相关
    • open(protocol):用给定的IP协议(v4或者v6)打开一个socket。主要用在UDP客户端 或者 服务端socket
    • bind(endpoint):将套接字绑定到一个地址和端口
    • connect(endpoint):Client用同步的方式连接到Server
    • async_connect(endpoint, handler):Client用异步的方式连接到Server,连接成功后,调用handler回调函数。
    • close():这个函数用来关闭套接字。
    TCP读写相关
    • async_read_some(buffer,handler):从套接字异步接收数据。接收完成后,调用handler回调函数。
    • async_write_some(buffer, handler):异步发送缓冲区数据到套接字。发送完成后,调用handler回调函数。
    • read_some(buffer):同步地从所给的缓冲区读取数据。在读完所有数据或者错误出现之前,这个函数都是阻塞的。
    • write_some(buffer):同步地发送缓冲区的数据。在所有数据发送成功或者出现错误之前,这个函数都是阻塞的。
    其他方法
    • local_endpoint():这个方法返回套接字本地连接的地址。
    • remote_endpoint():这个方法返回套接字连接到的远程地址。
    • non_blocking():如果套接字是非阻塞的,这个方法返回true,否则false。
    ( ps:为了使socket和缓冲区(read或者write)在整个异步操作的生命周期中一直活动,需要采取特殊的防护措施。连接类需要继承自enabled_shared_from_this,然后在内部保存它需要的缓冲区,而且每次异步调用都要传递一个智能指针给this操作。)
     
    3. 使用boost::asio实现TCP客户端和服务器端:
    (1)Server端:
    #include <iostream>
    #include <boost/shared_ptr.hpp>
    #include <boost/asio.hpp>
    #include <boost/asio/placeholders.hpp>
    #include <boost/system/error_code.hpp>
    #include <boost/bind/bind.hpp>
    #include "stdafx.h"
    
    using namespace boost::asio;
    using namespace std;
    typedef boost::shared_ptr<ip::tcp::socket> sock_ptr;
    
    class server
    {
    private:
        io_service m_io;
        ip::tcp::acceptor m_acceptor;
    
    public:
        server() : m_acceptor(m_io, ip::tcp::endpoint(ip::tcp::v4(), 6688))
        { accept(); }
    
        void run(){ m_io.run();}
    
        void accept()
        {
            sock_ptr sock(new ip::tcp::socket(m_io));
            m_acceptor.async_accept(*sock, boost::bind(&server::accept_handler, this, boost::asio::placeholders::error, sock));
        }
    
        void accept_handler(const boost::system::error_code& ec, sock_ptr sock)
        {
            if (ec)
            { 
                return; 
            }
            cout<<"Client:";
            cout<<sock->remote_endpoint().address()<<endl;
            sock->async_write_some(buffer("hello asio"), boost::bind(&server::write_handler, this, boost::asio::placeholders::error));
            // 发送完毕后继续监听,否则io_service将认为没有事件处理而结束运行 
            accept();
    }
    
        void write_handler(const boost::system::error_code&ec)
        {
            cout<<"send msg complete"<<endl;
        }
    };
    
    int main()
    {
        try
        {
            cout<<"Server start."<<endl;
            server srv;
            srv.run();
        }
        catch (std::exception &e)
        {
            cout<<e.what()<<endl;
        }
        return 0;
    }
     
    (2)Client端:
    #include <iostream>
    #include <boost/shared_ptr.hpp>
    #include <boost/asio.hpp>
    #include <boost/asio/placeholders.hpp>
    #include <boost/system/error_code.hpp>
    #include <boost/bind/bind.hpp>
    #include "stdafx.h"
    
    using namespace boost::asio;
    using namespace std;
    
    typedef boost::shared_ptr<ip::tcp::socket> sock_ptr;
    typedef vector<char> buffer_type;
    
    class client
    {
    
    private:
        io_service m_io;
        buffer_type m_buf;
        ip::tcp::endpoint m_ep;
    public:
        client(): m_buf(100, 0),  m_ep(ip::address::from_string("127.0.0.1"), 6688)
        { start(); }
    
        void run()
        { m_io.run();}
    
        void start()
        {
            sock_ptr sock(new ip::tcp::socket(m_io));
            sock->async_connect(m_ep, boost::bind(&client::conn_handler, this, boost::asio::placeholders::error,     sock));
        }
    
        void conn_handler(const boost::system::error_code&ec, ip::tcp::socket sock)
        {
            if (ec)
            {return;}
            cout<<"Receive from "<<sock->remote_endpoint().address()<<": "<<endl;
            sock->async_read_some(buffer(m_buf), boost::bind(&client::read_handler, this, boost::asio::placeholders::error, sock));
        }
    
        void read_handler(const boost::system::error_code&ec, ip::tcp::socket sock)
        {
            if (ec)
            {return;}
            sock->async_read_some(buffer(m_buf), boost::bind(&client::read_handler, this, boost::asio::placeholders::error, sock));
            cout<<&m_buf[0]<<endl;
        }
    };
    
    int main()
    {
        try
        {
            cout<<"Client start."<<endl;
            client cli;
            cli.run();
        }
        catch (std::exception &e)
        {
            cout<<e.what()<<endl;
        }
        return 0;
    }
  • 相关阅读:
    SuperMap房产测绘成果管理平台
    SuperMap产权登记管理平台
    Android adb shell am 的用法(1)
    由浅入深谈Perl中的排序
    Android 内存监测和分析工具
    Android 网络通信
    adb server is out of date. killing...
    引导页使用ViewPager遇到OutofMemoryError的解决方案
    adb logcat 详解
    How to send mail by java mail in Android uiautomator testing?
  • 原文地址:https://www.cnblogs.com/ladawn/p/8459701.html
Copyright © 2011-2022 走看看