zoukankan      html  css  js  c++  java
  • [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());   
    }  
  • 相关阅读:
    一些你可能用到的代码
    iOS 键盘下去的方法
    iOS设计模式汇总
    随笔
    Spring cloud config 分布式配置中心 (三) 总结
    Spring cloud config 分布式配置中心(二) 客户端
    Spring cloud config 分布式配置中心(一) 服务端
    jdbcUrl is required with driverClassName spring boot 2.0版本
    JpaRepository接口找不到 spring boot 项目
    解决IntelliJ “Initialization failed for 'https://start.spring.io'
  • 原文地址:https://www.cnblogs.com/pangblog/p/3290057.html
Copyright © 2011-2022 走看看