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类对应socketAPI的accept()函数功能,它用于服务器端,在指定的端口号接受连接,必须配合socket类才能完成通信。
resolver类对应socketAPI的getaddrinfo()系列函数,用于客户端解析网址获得可用的IP地址,解析得到的IP地址可以使用socket对象连接。
下面是一个使用socket类和acceptor类来实现一对同步通信的服务器和客户端程序:服务器端(它使用一个acceptor对象在6688端口接受连接,当有连接时使用一个socket对象发送一个字符串):同步socket处理服务器端:server.cpp#include "boost/asio.hpp"#include "boost/date_time/posix_time/posix_time.hpp"#include "boost/bind.hpp"#include "boost/function.hpp"#include "iostream"using namespace std; int main(){ try //function-try 块 { cout << "server start" << endl; boost::asio::io_service ios; //asio程序必须的io_service对象 boost::asio::ip::tcp::acceptor acceptor(ios, //创建acceptor对象,iPv4 boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 7001)); //接受7001端口 cout << acceptor.local_endpoint().address() << endl; while (true) //执行循环服务 { boost::asio::ip::tcp::socket sock(ios); //一个socket对象 acceptor.accept(sock); //阻塞等待socket连接 cout << "client : "; cout << sock.remote_endpoint().address() << endl; sock.write_some(boost::asio::buffer("hello asio")); //发送数据 } }catch (std::exception& e) //捕获可能发生的异常 { cout << e.what() << endl; } return 0;}注:要注意的是*函数buffer(),它可以包装很多种类的容器成为asio组件可用的缓存区类型。通常我们不能把数组、vector等容器用作asio的读写参数,必须使用buffer()函数包装。 客户端 client.cpp#include "boost/asio.hpp"#include "boost/date_time/posix_time/posix_time.hpp"#include "boost/bind.hpp"#include "boost/function.hpp"#include "iostream"using namespace std;#include "vector" class a_timer{ public: template<typename F> //模板类型,可以接受任意可调用物 a_timer(boost::asio::io_service& ios, int x, F func) :f(func), count_max(x), count(0), //初始化回调函数和计数器 t(ios, boost::posix_time::millisec(500)) //启动计时器 { t.async_wait(boost::bind(&a_timer::call_func, //异步等待计时器 this, boost::asio::placeholders::error)); //注册回调函数 } void call_func(const boost::system::error_code& ) { if (count >= count_max) // 如果计数器达到上限则返回 { return; } // ++count; f(); // 调用function对象 // 设置定时器的终止时间为0.5秒之后 t.expires_at(t.expires_at() + boost::posix_time::microsec(500)); // 再次启动定时器,异步等待 t.async_wait(boost::bind(&a_timer::call_func,this, boost::asio::placeholders::error));} private: int count; //计时器成员变量 int count_max;boost::function<void()> f; // function对象,持有无参无返回值的可调用物 boost::asio::deadline_timer t; // asio定时器对象 }; void client(boost::asio::io_service& ios) //传入io_service对象{try{cout << "client start." << endl; boost::asio::ip::tcp::socket sock(ios); //创建socket对象//创建连接端点boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 7001); sock.connect(ep); //socket连接到端点 vector<char> str(100, 0); //定义一个vector缓冲区sock.read_some(boost::asio::buffer(str)); //使用buffer()包装缓冲区接收数据 cout << "recive from" << sock.remote_endpoint().address();cout << &str[0] << endl; //输出接收的字符串}catch (std::exception& e) { cout << e.what() << endl; } //捕获可能发生的异常} //然后在main()函数中创建io_service对象,用启动器启动socket客户端:int main(){boost::asio::io_service ios;a_timer at(ios, 5, boost::bind(client, boost::ref(ios)));ios.run(); //启动定时器return 0;}
异步socket处理服务器端:server.cpp
#include "boost/asio.hpp"//#include "boost/date_time/posix_time/posix_time.hpp"#include "boost/bind.hpp"//#include "boost/function.hpp"#include "iostream"
using namespace std;using namespace boost;//首先定义一个server类,它实现异步服务的所有功能//server类必须的成员变量是io_service对象和acceptor对象,他们的是TCP通信的必备要素//还定义了一个只能指针的typedef,它指向socket对象,用来在回调函数中和传递。class server{private:boost::asio::io_service &ios;boost::asio::ip::tcp::acceptor acceptor;typedef boost::shared_ptr<boost::asio::ip::tcp::socket> sock_pt;
//server的构造函数存储io_service对象,使用ios、tcp协议和端口号初始化acceptor对象//并用start()函数立即启动异步服务public:server(boost::asio::io_service& io) : ios(io), acceptor(ios,boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),7004)){ start(); }
//start()函数用于启动异步接受连接,需要调用acceptor的async_accept()函数。//为了让socket对象能够被异步调用后还能使用,我们必须使用shared_ptr来创建socket对象的//智能指针,他可以在程序的整个生命周期中存在,直到没人使用它为止。void start(){sock_pt sock(new boost::asio::ip::tcp::socket(ios)); //智能指针acceptor.async_accept(*sock,boost::bind(&server::accept_handler,this,boost::asio::placeholders::error,sock)); //异步侦听服务}//当有TCP连接发生时,server::accept_handler()函数将被调用,它使用socket对象发送数据void accept_handler(const boost::system::error_code& ec,sock_pt sock){if(ec) //检验错误码{ return; }cout << "client:"; //输出连接的客户端信息cout << sock->remote_endpoint().address() << endl;sock->async_write_some(boost::asio::buffer("hello asio"),boost::bind(&server::write_handler, this,boost::asio::placeholders::error));start(); //再次启动异步接受连接}//首先它必须检测asio传递的error_code,保证没有错误发生。然后调用socket对象的//async_write_some()异步发送数据。同样,我们必须再为这个异步调用编写回调函数//write_handler()。当发送完数据后不要忘记调用start()再次启动服务器接受连接,//否则当完成数据发送后io_service将因为没有时间处理而结束运行。
//发送数据的回调函数write_handler()很简单,可以直接实现一个空函数,这里输出一条信息//表示异步发送数据完成void write_handler(const boost::system::error_code& error){ cout << "send msg complete," <<endl; }};
//最后在main()函数中创建io_service对象和server对象,调用run()方法开始异步等待int main()try{cout << "server start." <<endl;boost::asio::io_service ios; //io_service对象server serv(ios); //构造server对象ios.run();}catch (std::exception& e) //捕获可能发生的异常{cout << e.what() <<endl;}
客户端:client.cpp
//通常客户端不需要使用异步通信,出于学习,这里也实现异步的客户端,示范asio的异步用法。#include<iostream>#include<boost/asio.hpp>#include<boost/bind.hpp>
using namespace std;//与服务器端对象,这里需要定义一个client类,实现所有异步调用功能//client与server类相同,都必须持有一个io_service的应用,也要有一个socket的share_ptr//不同的是client不需要acceptor,而是使用一个端点直接与服务器建立连接。class client{private:boost::asio::io_service& ios; //io_service对象boost::asio::ip::tcp::endpoint ep; //TCP端点typedef shared_ptr<boost::asio::ip::tcp::socket> sock_pt;//client构造函数的主要作用是初始化IP端点对象,并调用start()函数启动TCP连接public:client(boost::asio::io_service& io):ios(io),ep(boost::asio::ip::address::from_string("127.0.0.1"),7004){ start(); } //启动异步连接//start()创建一个socket独享的智能指针以便在异步调用过程中传递,//然后使用async_connect()启动一个异步连接,指定连接的处理函数是conn_handler()void start(){sock_pt sock(new boost::asio::ip::tcp::socket(ios));sock->async_connect(ep,boost::bind(&client::conn_handler, this, boost::asio::placeholders::error, sock));}//当异步连接成功时,conn_handler()将被调用,它再用shared_ptr包装vector//用buffer()函数把vector作为接收数据的缓冲区,由async_read_some()异步读取//然后再启动一个异步连接void conn_handler(const boost::system::error_code& ec, sock_pt sock){if(ec) //处理错误代码{ return ; }cout << "revice from" << sock->remote_endpoint().address();boost::shared_ptr<vector<char> > str(new vector<char>(100,0)); //建立接收数据的缓冲区sock->async_read_some(boost::asio::buffer(*str), //异步读取数据boost::bind(&client::read_handler, this, boost::asio::placeholders::error, str));start(); //再次启动异步连接}//当异步读取结束时read_handler()被调用,它直接输出shared_ptr指向的缓冲区内容void read_handler(const boost::system::error_code& ec,boost::shared_ptr<vector<char> > str){if(ec) //处理错误代码{ return; } cout << &(*str)[0] <<endl; //输出接收到的数据}};//客户端的main()函数代码与服务器端的完全一致int main(){try{cout << "client start." << endl;boost::asio::io_service ios;client c1(ios);ios.run();}catch(std::exception& e) //捕获可能发生的异常{cout << e.what() <<endl;}}
相关文章
- 嵌入式学习37-TCP并发模型-有限 2.IO模型: 1.阻塞IO: 没有数据到来时,可以让任务挂起 节省CPU资源开销,提高系统效率 2.非阻塞IO: 程序未接收到数据时一直执行 效率很低 3.异步IO 只能绑定一个文件描述符用来 读取数据 4.多路复用IO select 1.select监听的集合中的文件描述符有 上限限制 2.select有 内核层 向 用户层数据空间 拷贝 的过程,占用系统资源开销 3.select必须 轮询检测 产生 事件 的文件描述符 4.select 只能工作 在 水平触发 模式(低速模式) 无法工作 在 边沿触发 模式(高速模式) poll (监听的集合中的文件描述符有 没有上限限制) 1.poll有 内核层 向 用户层 数据空间 拷贝 的过程,占用系统资源开销 2.poll必须 轮询检测 产生 事件 的文件描述符 3.poll 只能工作在水平触发模式(低速模式) 与select相同 无法工作在边沿触发(高速模式) 3.函数接口: 1.select int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 功能: select 监听 文件描述符集合 中 是否 有文件描述编程 ready状态 select 监听 文件描述符集合 中 ,若有状态 , 将没有ready状态的T除 若无状态,将阻塞继续等待 参数: nfds: 最大文件描述符的值 +1 readfds: 读 文件描述符集合 writefds: 写 文件描述符集合 exceptfds: 其余 文件描述符集合 timeout: 等待的时长 NULL 一直等待(超时处理) 返回值: 成功 返回 文件描述符集合中 的 文件描述符个数 失败 返回 -1 void FD_CLR (int fd, fd_set *set); 功能: 将文件描述符 fd 从集合中清除
- QUnit使用笔记-2同步与异步处理方式
- boost-asio学习1——定时器(同步、异步)
- boost库学习随记六:使用同步定时器、异步定时器、bind、成员函数回调处理、多线程的同步处理示例等
- boost-asio学习2——同步、异步socket处理
- boost-asio学习1——定时器(同步、异步)
- boost-asio学习2——同步、异步socket处理