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;
    }
  • 相关阅读:
    java连接常见数据库的连接字符串
    一个用来自动管理大容量表的Sql脚本
    Ibatis2.0使用说明(一)——入门实例篇
    态度决定你的人生高度
    jboss配置入门(二) -JBOSS3.2.3/3.2.6部署及配置修改
    如何在一个工程里面实现不同的功能打入不同的日志文件中【log4net】
    Xsl实践总结(一)
    Xsl实践总结(三)-介绍一款开发XSL不错的IDE(Stylus)
    Xsl实践总结(二)
    教你节省时间 让你个人效率翻三倍
  • 原文地址:https://www.cnblogs.com/ladawn/p/8459701.html
Copyright © 2011-2022 走看看