boost库::asio库的TCP连接以及类详细摘要

asio库的简明笔记
boost库作为C++准标准库,特别是类摘要写的极其规范和简明,是一个榜样。

1 头文件

#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;

2 boost::asio::io_service

负责事件的处理

class io_servie :private nocopyable // 不可拷贝,将拷贝和赋值给DELETE了
{
    public:
    run(); 		 // 阻塞事件循环
    run_one();   // 阻塞一个
    poll();		 // 非阻塞执行一个ready的handler
    poll_one();
    stop();			//	停止
    stopped()const;	// 确认是否停止
    reset();		// 重启
    class work;		// 很重要,用io_servie持续工作
};

最常用的就是run()函数,它启动事件的循环,阻塞等待注册的回调函数完成任务。

2 socket类

class basic_stream_socket{
   public:
    explicit basic_stream_socket(io_service& io_service);
    // 拒绝隐式转换 用Io_service 实体类对其进行初始化
    // move的移动构造函数
    basic_stream_socket(io_service&& other);
    void open(const protocol_type& protocol=protocol_type());
    void close();
    void connect(const endpoint_type& peer_endpoint);
    // 连接端点信息
    size_t send(const ConstBuffer& buffers);
    // 发送数据
    size_t async_send(const ConstBuffer& buffers,handler);
    // 异步发
    size_t async_receive(const MutableBuffer& buffers,handler);
    size_t async_write_some(const ConstBuffer& buffers,handler);
    // 异步接收,异步写
    endpoint_type local_endpoint() const;
    endpoint_type remote_endpoint() const;
    // 本地和远端 端点信息
    size_t available() const;
    // 可读取的字节数
};
  • socket在构造时指定协议或dpoint,或者稍后调用成员函数connect
  • 连接成功后,使用local_endpointremote_endpoint来获取端点信息
  • 用available()成员函数来获取可读取的字节数
  • 用send和receive来接收被buffer包装的任意类型的数据
  • socket会自动调用析构来close()掉socket对象

io_service 是关键,程序和操作系统之间的桥梁

需要通过它注册回调, 在Linux下调用epoll,在Windows调用IOCP

tcp::resolver::query

query和iterator共同完成查询IP地址的工作

网址+服务名(或者端口号)创建query对象。

tcp::resolver::iterator

然后由resolve成员函数中,将query对象作为参数,生成iterator对象

关键性示例代码

tcp::resolver reslover(io_service); 			// 创建reslover对象
tcp::resolver::query query(argv[1],"daytime");  // IP地址+服务号
tcp::resolver::iterator endpoint_iterator =reslover.resolve(query); // 完成查询工作
tcp::socket socket(io_service);					// 创建socket对象
boost::asio::connect(socket,endpoint_iterator);	// 进行连接

这个对象实例可以与socket类的对象进行建立连接。

#include "tcp.hpp"
int main(int argc,char *argv[]){
    
    boost::asio::io_service io_service;
    // io_service 是关键,程序和操作系统之间的桥梁
    // 需要通过它注册回调, 在Linux下调用epoll,在Windows调用IOCP
    tcp::resolver reslover(io_service);
    // resolver 解析我们的IP地址,argv[1]传入ip地址
    
    // 参数1:也可以传入一个网址,通过DNS再解析出来IP地址 
    // 参数2:daytime字符串,通过配置的端口号,或者一个端口号
    // 由reslove去完成·
    tcp::resolver::query query(argv[1],"daytime"); // query访问服务 daytime是服务器端和客户端主动断开的

    tcp::resolver::iterator endpoint_iterator =reslover.resolve(query);
    // resolve 将地址返回出来了
    tcp::socket socket(io_service);
    boost::asio::connect(socket,endpoint_iterator);
    
    for(;;) {
        boost::array<char,128> buf; 		// 数据缓冲区
        boost::system::error_code error;    // 错误码,这个出错会给error赋值

        // read_some是阻塞式的,不清楚对方传过来多少字节,或者下载文件
        // 如果做游戏就不行
        
        size_t len = socket.read_some(boost::asio::buffer(buf),error);
        // 读取被buffer包装后的数据

        if(error == boost::asio::error::eof) break;
        else if (error)
            throw boost::system::system_error(error);
        std::cout.write(buf.data(),len);
    }
}

./a.out time.nist.gov

测试结果

59504 21-10-17 13:04:54 22 0 0 310.6 UTC(NIST) *

3 acceptor类

对应负责的就是accept函数的封装

class basic_socket_acceptor
{
public:
	typedef Protocol protocol_type;
    typedef typename Protocol::endpoint endpoint_type;	// 用于对端点的连接
    explicit basic_socket_acceptor(io_service &io);
    basic_socket_acceptor(io_service &io,const endpoint_type& endpoint);
    // 直接在构造函数中设置端点信息
    void accept(socket& peer); // 建立连接
    void set_option();		   // 略,设置socket
    void accept(socket& peer,endpoint_type &p); // 连接时设置端点信息
    void async_accept();	   // 异步连接
};

好了

现有io_serivce socket类,还有acceptor,就需要设置一下端点信息了,毕竟只有端点知道了才能建立连接。

4 endpoint类

class basic_endpoint
{
 public:
    explicit basic_endpoint(const ip::address& addr,unsigned short port_num);
    									// 设置IP地址和端口号,IP地址又需要address类
    unsigned short port() const;		// 获取端口号
    void port(unsigned short port_num); // 设置端口号
    ip::address address()const;			// 获取地址
    void address(ip::address &addr);	// 设置地址
};

设置IP地址又需要address类

5 address类

class address{
  public:
    address();
    address(const address& other);
    bool is_v4() const;
    bool is_v6() const;	//是否IPv4和v6
    bool is_loopback(); //是否回环
    ip::address_v4 to_v4()	const; // 转成v4
    string to_string() const;	   // 将地址转为字符串
    static address from_string(const char* str);	// 从字符串构造
    static address from_string(const string& str);
    friend bool operator==(const address& a1,const address &a2);
    // 其他比较和流重载
};

详细用例

ip::address addr;
addr = addr.from_string("127.0.0.1");
assert(addr.is_v4());		// 断言判断是否v4
cout<<addr.to_string()<<endl;
addr = addr.from_string("ab::12:34:56");
assert(addr.is_v6());

6 组合用例

ip::address addr;
addr = addr.from_string("127.0.0.1");
ip::tcp::endpoint ep(addr,6688);	// 设置IP和端口号

server.cpp

#include <boost/asio.hpp>   
#include <iostream>
#include <vector>
using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;
int main() {
    try
    {
        
        io_service io;
        tcp::acceptor acceptor(io,tcp::endpoint(tcp::v4(),6688));
        // 创建acceptor对象 ipv4 接收6688端口连接
        // 开始监听

        cout<<acceptor.local_endpoint().address()<<endl;
        for(;;)
        {
            tcp::socket sock(io);   // 创建socket对象
            acceptor.accept(sock);  // 阻塞等待socket连接
            cout<<"client ……"<<endl;
            cout<<sock.local_endpoint().address()<<endl;
            sock.send(buffer("hello asio"));
        }
        
    }
    catch(const std::exception& e)
    {
        std::cerr << e.what() << '\n';
    }
    
}
  1. 创建io_service io对象

  2. 创建ip::address对象设置IP地址和端口号

  3. 通过address构造tcp::acceptor 设置服务于socket对象的端点信息

  4. 用io对象构建socket对象

  5. 如果是异步,就需要在io里面注册回调函数

  6. socket对象 调用accpet()函数

  7. 用buffer可以包装任意数据类型,且buffer是一个工厂函数

  8. async_send或者recv去接收数据

    client.cpp

    #include <boost/asio.hpp>   
    #include <iostream>
    #include <vector>
    using namespace std;
    using namespace boost;
    using namespace boost::asio;
    using namespace boost::asio::ip;
    int main()
    {
        try
        {
            cout<<"client begin()……"<<endl;
            io_service io;
            tcp::socket sock(io);
            tcp::endpoint ep(ip::address::from_string("127.0.0.1"),6688);
            sock.connect(ep);
            cout<<sock.available()<<endl;
            vector<char> str(sock.available()+1,0);
            // 定义缓冲区
            sock.receive(buffer(str));  // 包装缓冲区
            for(int i=0;i<str.size();i++)
            cout<<str[i]<<endl;
    
        }
        catch(const std::exception& e)
        {
            std::cerr << e.what() << '\n';
        }
    }
    
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值