• [Boost基础]并发编程——asio网络库——同步socket处理


    网络通信简述

    asio库支持TCP,UDP和ICMP通信协议,它在名字空间boost::asio::ip里提供了大量的网络通信方面的函数和类,很好的封装了原始的Berkeley Socket API,展现给asio用户一个方便易用且健壮的网络通信库。

    ip::tcp类是asio网络通信(TCP)部分主要的类,但它本身并没有太多的功能,而且定义了数个用于TCP通信的typedef类型,用来协作往常网络通信。这些typedef包括端点类endpoint,套接字类socket,流类iostream,以及接收器acceptor,解析器resolver等等。从某种程度上来看,ip::tcp类更像是一个名字空间。

    ip::tcp的内部类型socket,acceptor和resolver是asio库TCP通信中最核心的一组类,他们封装了socket的连接  ,断开和数据收发功能,使用他们可以很容易的编写出socket程序。

    • socket类是TCP通信的基本类,调用成员函数connect()可以连接到一个指定的通信端点,连接成功后用local_endpoint()和remote_endpoint()获得连接两端的端点信息,用read_some和write_some阻塞读写数据,当操作往常后使用close()函数关闭socket.如果不关闭socket,那么socket对象析构是也会自动调用close()关闭。
    • acceptor类对于的socket API的accept()函数功能,他用于服务器端,在指定的端口号接受连接,必须配合socket类才能完成通信。
    • resolver类对应socket API的getaddrinfo系列函数,用于客户端解析网址获得可用的IP地址,解析得到的IP地址可用使用socket对象连接。

    同步服务器端

    #include <conio.h>
    #include <iostream>
    using namespace std;
    #include <boost/asio.hpp>
    using namespace boost;
    using namespace boost::asio;
    //同步server----它用一个acceptor对象在6688端口接受连接,当有连接是使用一socket对象发送一个字符串
    void test1()
    {
        try
        {
            io_service ios;
            ip::tcp::acceptor acceptor(ios,ip::tcp::endpoint(ip::tcp::v4(),6688));
            cout<<acceptor.local_endpoint().address()<<endl;
            while(true)
            {
                ip::tcp::socket sock(ios);
                acceptor.accept(sock);//阻塞等待socket连接
                cout<<"client:ip:"<<sock.remote_endpoint().address()<<"   port:"<<sock.remote_endpoint().port()<<endl;
                sock.write_some(buffer("hello asio"));
                //服务器端程序里要注意的是自由函数buffer(),它可用包装很多种类的容器成为asio组件可用的缓冲区类型。通常我们不能直接把数组,vector等容器用作asio的读写参数,必须使用buffer()函数包装。
            }
        }
        catch(std::exception& e)
        {
            cout<<e.what()<<endl;
        }
    } 
    void test2()
    {
    }
    void test3()
    {
    
    }
    void test(char t)  
    {  
        std::cout<<"press key====="<<t<<std::endl;  
        switch (t)  
        {    
        case '1':test1();break;   
        case '2':test2();break;   
        case '3':test3();break;   
        case 27:  
        case 'q':exit(0);break;  
        default: std::cout<<"default "<<t<<std::endl;break;  
        }  
    }  
    void main()
    {
        while (1)
        {
            test(getch());
        }
    }

    同步客户端

    #include <conio.h>
    #include <iostream>
    using namespace std;
    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    using namespace boost;
    using namespace boost::asio;
    
    //IP地址和端点      
    //IP地址独立于TCP,UDP等通信协议,asio库使用类ip::address来表示IP地址,可以同时支持ipv4和ipv6两种地址。
    void test1()
    {
        ip::address addr=addr.from_string("127.0.0.1");
        assert(addr.is_v4());
        cout<<addr.to_string()<<endl;
        addr=addr.from_string("ab::12:34:56");
        assert(addr.is_v6());
    //有了ip地址,再加上通信用的端口就构成了一个socket端点,在asio库中用ip::tcp::endpoint类来表示。
        ip::address addr1=addr1.from_string("127.0.0.1");
        ip::tcp::endpoint ep(addr1,6688);//创建一个端点对象,端口为6688
        assert(ep.address()==addr1);
        assert(ep.port()==6688);
    }
    //同步socket处理
    class a_timer
    {
    private:
        int count,cout_max; //计数器成员变量
        function<void()> f; //function对象,持有无参数无返回的可调用物
        deadline_timer t;//asio定时器
    public:
        //构造函数初始化成员变量,将计数器清理,设置计数器的上限,拷贝存储回调函数,并立即启动定时器
        //之所以要"立即"启动,是因为我们必须包装在io_service.run()之前至少有一个异步操作在执行,否则io_service.run()会因为没有事件处理而立即不等待返回。
        template<typename F>a_timer(io_service& ios,int x,F func):f(func),cout_max(x),count(0),t(ios,posix_time::microsec(500))//模板类型,可接受任意可调用物
        {
            t.async_wait(bind(&a_timer::call_func,this,placeholders::error));//命名空间下asio::placeholders的一个占位符error,他的作用类似于bind库的占位符_1,_2,用于传递errror_code值。
        }
    
        //call_func()内部累加计数器,如果计数器未达到上限则调用function对象f,然后重新设置定时器的终止时间,再次异步等待被调用,从而达到反复执行的目的。
        void call_func(const boost::system::error_code &)
        {
            if(count >= cout_max)
            {
                return;
            }
            ++count;
            f();
            t.expires_at(t.expires_at()+posix_time::millisec(500));//设置定时器的终止时间为0.5秒之后
            t.async_wait(bind(&a_timer::call_func,this,placeholders::error));
        }
    };
    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"),6688);//创建连接端点
            sock.connect(ep);//socket连接到端点
            vector<char> str(100,0);//定义一个vector缓冲区
            sock.read_some(buffer(str));//使用buffer()包装缓冲区接收数据
            cout<<"recive from: ip:"<<sock.remote_endpoint().address()<<" port:"<<sock.remote_endpoint().port()<<endl;
            cout<<"recv:"<<&str[0]<<endl;//输出接收到的数据
        }
        catch(std::exception& e)
        {
            cout<<e.what()<<endl;
        }
    }
    //同步客户端
    void test2()
    { 
        io_service ios;
        a_timer at(ios,5,bind(client,ref(ios)));
        ios.run();
    }
    void test3()
    {
    }
    void test(char t)  
    {  
        std::cout<<"press key====="<<t<<std::endl;  
        switch (t)  
        {    
        case '1':test1();break;   
        case '2':test2();break;   
        case '3':test3();break;   
        case 27:  
        case 'q':exit(0);break;  
        default: std::cout<<"default "<<t<<std::endl;break;  
        }  
    }  
    void main()  
    {  
        while(1)   
            test(getch());   
    }  
  • 相关阅读:
    JAVA并发之ReentrantLock源码(一)
    java并发之线程池
    Quine--输出程序源码的程序(java)
    【leetcode】Weekly Contest 92
    【java集合类】ArrayList和LinkedList源码分析(jdk1.8)
    【leetcode】Weekly Contest 91
    牛客2018.6模拟考编程题
    MFC 完全自定义控件
    图形学中求平面方程系数以及法向量
    std::function解决函数重载绑定
  • 原文地址:https://www.cnblogs.com/pangblog/p/3290057.html
Copyright © 2020-2023  润新知