首页 > 其他分享 >boost asio相关的使用-基本概念

boost asio相关的使用-基本概念

时间:2023-06-30 19:12:30浏览次数:43  
标签:asio 调用 service ip tcp endpoint func boost 基本概念

1端点

boost asio 的endpoint的使用,可以将ip和端口合并成一个端点(endpoint),端点是使用某个端口连接到的一个地址。不同类型的socket有它自己的endpoint类,比如ip::tcp::endpoint、ip::udp::endpoint和ip::icmp::endpoint

如果想连接到本机的80端口,你可以这样做: ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80);

有三种方式来让你建立一个端点:
1) endpoint():这是默认构造函数,某些时候可以用来创建 UDP/ICMP socket 。
2)endpoint(protocol, port) :这个方法通常用来创建可以接受新连接的服务器端 socket 。
3)endpoint(addr, port) 这个方法创建了一个连接到某个地址和端口的端点。

例子如下:  ip::tcp::endpoint ep1;

                    ip::tcp::endpoint ep2(ip::tcp::v4(), 80);

                    ip::tcp::endpoint ep3( ip::address::from_string("127.0.0.1), 80);

如果你想连接到一个主机(不是IP地址),你需要这样做:

// 输出 "87.248.122.122"
 io_service service; 
ip::tcp::resolver resolver(service);
ip::tcp::resolver::query query("www.yahoo.com", "80"); 
ip::tcp::resolver::iterator iter = resolver.resolve( query);
ip::tcp::endpoint ep = *iter; std::cout << ep.address().to_string() << std::endl;

你可以用你需要的socket类型来替换tcp。首先,为你想要查询的名字创建一个查询器,然后用resolve()函数解析它。如果成功,它至少会返回一个入口。你可以利用返回的迭代器,使用第一个入口或者遍历整个列表来拿到全部的入口。

如何遍历?

#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using namespace std;
using boost::asio::ip::tcp;
int main(int argc, const char** argv) {
  boost::asio::io_service ioservice;
  tcp::resolver resolver(ioservice);
  tcp::resolver::query query("www.google.com", "80");
  tcp::resolver::iterator it = resolver.resolve(query);
  tcp::resolver::iterator end;
  
  while(it!=end)
  {
    tcp::endpoint ep = *it;
    it++;
    std::cout << ep.address().to_string() << "," << ep.port() << std::endl;
  }
  
  return 0;
}

给定一个端点,可以获得他的地址,端和IP协议(v4或者v6):

std::cout << ep.address().to_string() << ":" << ep.port() << "/" << ep.protocol() << std::endl;

 

io_service 异步的post,dispatch,wrap

解释y: 

post()会将Handler加入到任务队列中,然后在调用了run()、run_one()、 poll()、 poll_one()的线程中执行。post 优先将任务排进处理队列,然后返回,任务会在某个时机被完成。

dispatch()会先进行判断,如果执行dispatch的线程之后就会调用run()、run_one()、 poll()、 poll_one(),那么直接在当前线程执行。否则同post()。
dispatch会即时请求io_service去调用指定的任务

这取决于调用的上下文,即它是从 io_service 内部运行还是不从 io_service 内部运行:

  • post永远不会直接调用该函数,而是推迟调用。
  • dispatch如果调度调用者是从 io_service 本身调用的,则将立即调用它,否则将其排队。

Boost.Asio提供了三种让你把处理方法添加为异步调用的方式:
1)service.post(handler):这个方法能确保其在请求 io_service 实例,然后调用指定的
处理方法之后立即返回。 handler 稍后会在某个调用了 service.run() 的线程中被调用。
2) service.dispatch(handler):这个方法请求 io_service 实例去调用给定的处理方法,
但是另外一点,如果当前的线程调用了 service.run(),它可以在方法中直接调用
handler 。
3) service .wrap( handler):这个方法创建了一个封装方法,当被调用时它会调用
service.dispatch(handler) handler),这个会让人有点困惑,接下来我会简单地解释它是什么
意思。

using namespace boost::asio;
io_service service; 
void func(int i) { std::cout << "func called, i= " << i << std::endl; } 
void run_dispatch_and_post() 
{
     for ( int i = 0; i < 10; i += 2) { 
       service.dispatch(boost::bind(func, i)); 
       service.post(boost::bind(func, i + 1)); 
     } 
} 

int main(int argc, char* argv[])
 {
 service.post(run_dispatch_and_post);
 service.run(); 
}

 结果如下:

func called, i= 0 
func called, i= 2
 func called, i= 4 
func called, i= 6
 func called, i= 8 
func called, i= 1
 func called, i= 3 
func called, i= 5 
func called, i= 7
 func called, i= 9

 

偶数先输出,然后是奇数。这是因为我用dispatch()输出偶数,然后用post()输出奇数。dispatch()会在返回之前调用hanlder,因为当前的线程调用了service.run(),而post()每次都立即返回了。

现在,让我们讲讲service.wrap(handler)。wrap()返回了一个仿函数,它可以用来做另外一个方法的参数:

using namespace boost::asio;
io_service service; 
void dispatched_func_1() 
{
 std::cout << "dispatched 1" << std::endl;
 } 
void dispatched_func_2() { 
std::cout << "dispatched 2" << std::endl; 
} 

void test(boost::function<void()> func) { 
std::cout << "test" << std::endl; 
service.dispatch(dispatched_func_1); func();
} void service_run() { service.run(); } int main(int argc, char* argv[]) { test( service.wrap(dispatched_func_2)); boost::thread th(service_run); boost::this_thread::sleep( boost::posix_time::millisec(500));
th.join(); }

test(service.wrap(dispatched_func_2));会把dispatched_ func_2包装起来创建一个仿函数,然后传递给test当作一个参数。当test()被调用时,它会分发调用方法1,然后调用func()。这时,你会发现调用func()和service.dispatch(dispatched_func_2)是等价的,因为它们是连续调用的。

程序的输出证明了这一点:

      test

      dispatched 1

      dispatched 2

详见:

 https://blog.csdn.net/wojiuguowei/article/details/78392960

 

3.缓冲区封装函数

纵观所有代码,你会发现:无论什么时候,当我们需要对一个buffer进行读写操作时,代码会把实际的缓冲区对象封装在一个buffer()方法中,然后再把它传递给方法调用:

char buff[512];

sock.async_receive(buffer(buff), on_read);
基本上我们都会把缓冲区包含在一个类中以便Boost.Asio的方法能遍历这个缓冲区,比方说,

使用下面的代码: sock.async_receive(some_buffer, on_read);
实例some_buffer需要满足一些需求,叫做ConstBufferSequence或者MutableBufferSequence(你可以在Boost.Asio的文档中查看它们)。创建你自己的类去处理这些需求的细节是非常复杂的,但是Boost.Asio已经提供了一些类用来处理这些需求。所以你不用直接访问这些缓冲区,而可以使用buffer()方法。

自信地讲,你可以把下面列出来的类型都包装到一个buffer()方法中:
1. 一个 char[] const 数组
2. 一个字节大小的 void * 指针
3.  一个 std::string 类型的字符串
4.  一个 POD const 数组( POD 代表纯数据,这意味着构造器和释放器不做任何操作)
5. 一个 pod 数据的 std::vector
6.  一个包含 pod 数据的 boost::array
7. 一个包含 pod 数据的 std::array
下面的代码都是有效的:

struct pod_sample { int i; long l; char c; }; ... 

char b1[512];

void * b2 = new char[512];
std::string b3; b3.resize(128);
pod_sample b4[16];
std::vector<pod_sample> b5; b5.resize(16);
boost::array<pod_sample,16> b6;
std::array<pod_sample,16> b7;
sock.async_send(buffer(b1), on_read);
sock.async_send(buffer(b2,512), on_read);
sock.async_send(buffer(b3), on_read);
sock.async_send(buffer(b4), on_read);
sock.async_send(buffer(b5), on_read);
sock.async_send(buffer(b6), on_read);
sock.async_send(buffer(b7), on_read);



总的来说就是:与其创建你自己的类来处理ConstBufferSequence或者MutableBufferSequence的需求,不如创建一个能在你需要的时候保留缓冲区,然后返回一个mutable_buffers_1实例的类,而我们早在shared_buffer类中就这样做了。

 详细见:

https://www.cnblogs.com/milanleon/p/7609574.html

         

 

标签:asio,调用,service,ip,tcp,endpoint,func,boost,基本概念
From: https://www.cnblogs.com/bwbfight/p/17517463.html

相关文章

  • 储能系统双向DCDC变换器蓄电池充放电仿真模型有buck模式 储能系统双向DCDC变换器蓄电
    储能系统双向DCDC变换器蓄电池充放电仿真模型有buck模式储能系统双向DCDC变换器蓄电池充放电仿真模型有buck模式和boost模式,依靠蓄电池充放电维持直流母线电压平衡以某仿真为例子:文件下载后放到电脑桌面,注意不要自己新建文件夹再放入。将MATLAB工作目录设置为desktop,即桌面点击这......
  • 简单易学的机器学习算法——AdaBoost
    是符号函数。具体过程可见下图所示:(图片来自参考文件1)三、AdaBoost算法流程  上述为AdaBoost的基本原理,下面给出AdaBoost算法的流程:(来自参考文献2)四、实际的例子  AdaBoost算法是一种具有很高精度的分类器,其实AdaBoost算法提供的是一种框架,在这种框架......
  • 一个使用simulink搭建的三通道交错并联双向buck-boost变换器。它采用电压外环、三电流
    这是一个使用simulink搭建的三通道交错并联双向buck-boost变换器。它采用电压外环、三电流内环和载波移相120°的控制方式。该变换器在buck模式和boost模式之间切换时,能够实现能量的双向流动,而且不会产生过压和过流问题。交错并联的拓扑结构可以减少电感电流的纹波,减小每相电感的体......
  • vc6 配置使用 boost 1.34.1
    vc6配置使用boost1.34.1is2120于 2012-01-1314:17:05 发布2470 收藏分类专栏: c++ Boost 文章标签: python include library string 磁盘 cmd版权 c++同时被2个专栏收录61篇文章0订阅订阅专栏Boost8篇文章0订阅订阅专栏使用......
  • J2SE 基本概念和安装
    JDKvsJREvsJVMjdkvsjrevsjvm-JavaBeginnersTutorial 安装  Error/Exception ......
  • [QML]从零开始QML开发(二)QML开发,浅谈控件、槽函数、锚等基本概念。QML和C++怎么交互?贯
    [QML]从零开始QML开发(二)QML开发,浅谈控件、槽函数、锚等基本概念。QML和C++怎么交互?贯彻落实MVC原则先看代码:importQtQuick2.12importQtQuick.Window2.12importQtQuick.Controls2.5Window{visible:truewidth:320height:480title:qsTr("HelloW......
  • Android显示系统-基本概念梳理
    DisplayStatestructDisplayState{//这里定义了Display变更类型,说明Display可能发生的变化类型enum{eSurfaceChanged=0x01,eLayerStackChanged=0x02,eDisplayProjectionChanged=0x04,eDisplaySizeChanged=0x08,......
  • pg基本基本概念——模式、表、空间、用户间的关系
    表空间用于定义数据库对象在物理存储设备上的位置,不特定于某个单独的数据库。数据库是数据库对象的物理集合,而schema则是数据库内部用于组织管理数据库对象的逻辑集合,schema名字空间之下则是各种应用程序会接触到的对象,比如表、索引、数据类型、函数、操作符等。角色(用户)则是......
  • OGG基本概念
    OracleGoldenGate(OGG)基本概念目录OracleGoldenGate(OGG)基本概念1.OGG简介2.应用场景3.基本原理4.基本架构5.常用的拓扑结构6.支持的环境7.OGG安装部署1.OGG简介OGG是一种基于日志的结构化数据复制软件,它通过解析源数据库在线日志或归档日志获得数据的增删改变化(数据......
  • mysql索引和基本概念
    1.mysql索引和基本概念目录1.mysql索引和基本概念1.1.声明1.2.什么是索引1.3.二分查找法(BinarySearch)1.4.二叉查找树(BST)1.4.1.二叉树的特点1.4.2.二叉树存在的问题1.5.平衡二叉树(AVLTree)1.5.1.平衡二叉树的特点1.6.索引需要存储什么1.7.B树的特点1.7.1.B树是......