boost::asio::io_service与socket(C++)
2016-11-10 16:08
459 查看
boost::asio::io_service
io_service类为下面的异步对象提供核心的I/O操作函数,主要用途还是用于socket编程boost::asio::ip::tcp::socket
boost::asio::ip::tcp::acceptor
boost::asio::ip::udp::socket
boost::asio::deadline_timer
io_servie 实现了一个任务队列,io_servie最常用的两个接口是post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。Io_service是完全线程安全的队列。
【示例】
该示例通过创建io_service类对象,用于监听并处理tcp::socket线程,以socket形式向远端发送数据
//**********定义一个io_service类 boost::asio::io_service ioService; //**********定义一个socket类 //1、SendSocket为自定义的一个socket类; //2、SendSocket(boost::asio::io_service& ioService, const std::string& _server, uint16_t _port)为该类的构造函数,进行相应的初始化操作,其中ioService是上面定义的io_service类,_server是接收socket的服务器,_port接收socket服务器的端口; //3、socket(new tcp::socket(ioService))为启动的socket类型,此处是启用tcp类型,然后使该socket线程关联io_service,以便后续调用io_service类的先关函数; //4、queue是socket用来发送数据的缓存结构体; SendSocket::SendSocket(boost::asio::io_service& ioService, const std::string& _server, uint16_t _port) : socket(new tcp::socket(ioService)), packetNo(0), server(_server), port(_port), connecting(false), connected(false), sending(false), state(TS_RUNNING), sendCount(0), oldSendCount(0), lastLog(0) { if (!_server.empty()) serverAddress = boost::asio::ip::address::from_string(_server); queue = _queue = new PacketInfo(); } //**********守护io_service对象 //由于run函数在io事件完成后会退出,线程会终止,后续基于该对象的异步io任务无法得到调度。 boost::asio::io_service::work work(io_service); io_service.run();
【说明】
1、首先考察异步IO的处理流程
应用程序调用IO对象成员函数执行IO操作;
IO对象请求io_service的服务;
io_service 通知操作系统其需要开始一个异步连接;
操作系统指示连接操作完成, io_service从队列中获取操作结果;
应用程序必须调用io_service::run()以便于接收结果;
调用io_service::run()后,io_service返回一个操作结果,并将其翻译为error_code,传递到事件回调函数中;
2、然后考察io_service对象
io_service对象主要有两个方法——post和run:
post用于发布io事件,如timer,socket读写等,一般由asio框架相应对象调用,无需我们显式调用;
run用于监听io事件响应,并执行响应回调,对于异步io操作需要在代码中显式调用;
在异步io操作中需要我们手动调用run函数,基本工作模式如下:
等待io事件响应,如果所有io事件响应完成则退出;
等待到io事件响应后,执行其对应的回调;
继续等待下一个io事件,重复1-2;
在使用过程中一般有如下几个需要注意的地方:
1. run函数在io事件完成后会退出,导致后续基于该对象的异步io任务无法执行
由于io_service并不会主动调度线程,需要我们手动分配,常见的方式是给其分配一个线程,然后执行run函数。但run函数在io事件完成后会退出,线程会终止,后续基于该对象的异步io任务无法得到调度。解决这个问题的方法是通过一个asio::io_service::work对象来守护io_service。这样,即使所有io任务都执行完成,也不会退出,继续等待新的io任务。
boost::asio::io_service::work work(io_service); io_service.run();
WSAStartup和WSACleanup
WSAStartup与WSACleanup成对使用,WSAStartup的功能是初始化Winsock DLL,WSACleanup是来解除与Socket库的绑定并且释放Socket库所占用的系统资源。在Windows下,Socket是以DLL的形式实现的。在DLL内部维持着一个计数器,只有第一次调用WSAStartup才真正装载DLL,以后的调用只是简单的增加计数器,而WSACleanup函数的功能则刚好相反,每调用一次使计数器减1,当计数器减到0时,DLL就从内存中被卸载!因此,调用了多少次WSAStartup,就应相应的调用多少次的WSACleanup。
【函数原型】
int PASCAL FAR WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
【参数】
wVersionRequested:调用Windows Sockets API的版本;
lpWSAData :指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节;
【说明】
本函数必须是应用程序或DLL调用的第一个Windows Sockets函数.它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节.应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数。
【返回值】
成功 – 0
失败 –
WSASYSNOTREADY 指出网络通信依赖的网络子系统还没有准备好;
WSAVERNOTSUPPORTED 所需的Windows Sockets API的版本未由特定的Windows Sockets实现提供;
WSAEINVAL 应用程序指出的Windows Sockets版本不被该DLL支持;
getaddrinfo和struct addrinfo结构体
【函数原型】int getaddrinfo( const char *hostname, const char *service, const struct 4000 addrinfo *hints,struct addrinfo **result );
【参数】
hostname:一个主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串);
service:一个服务名或者10进制端口号数串;
hints:可以是一个空指针,也可以是一个指向某个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:如果指定的服务既支持TCP也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM,使得返回的仅仅是适用于数据报套接口的信息。
result :通过result指针参数返回一个指向addrinfo结构体链表的指针
【返回值】
0: 成功,返回非0: 出错。
【说明】
getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个sockaddr 结构的链而 不是一个地址清单。它具有协议无关性
结构体
struct addrinfo { int ai_flags; /* customize behavior */ int ai_family; /* address family */ int ai_socktype; /* socket type */ int ai_protocol; /* protocol */ socklen_t ai_addrlen; /* length in bytes of address */ struct sockaddr *ai_addr; /* address */ char *ai_canonname; /* canonical name of host */ struct addrinfo *ai_next; /* next in list */ . . . };
ai_family指定了地址族,可取值如下:
AF_INET 2 IPv4
AF_INET6 23 IPv6
AF_UNSPEC 0 协议无关
ai_socktype指定套接字的类型
SOCK_STREAM 1 流
SOCK_DGRAM 2 数据报
在AF_INET通信域中套接字类型SOCK_STREAM的默认协议是TCP(传输控制协议)
在AF_INET通信域中套接字类型SOCK_DGRAM的默认协议是UDP(用户数据报协议)
ai_protocol指定协议类型,可取的值取决于ai_address和ai_socktype的值,一般设置为0
相关文章推荐
- Boost.asio的简单使用(timer,thread,io_service类)
- boost::asio学习 - io_service的run,run_one,poll,poll_one的区别
- boost::asio学习 - io_service的run,run_one,poll,poll_one的区别
- boost.asio服务器使用io_service作为work pool
- boost asio io_service学习笔记
- Boost.asio的简单使用(timer,thread,io_service类)
- Boost::asio io_service 实现分析
- 【Boost】boost库asio详解2——io_service::run函数无任务时退出的问题
- Boost::asio io_service 实现分析
- Boost::asio io_service 实现分析
- boost::asio::Io_service
- boost::asio::Io_service
- boost asio io_service与 strand 分析
- Boost.asio的简单使用(timer,thread,io_service类)
- boost asio io_service学习笔记
- boost.asio服务器使用io_service作为work pool
- boost.asio服务器使用io_service作为work pool
- boost.asio系列——io_service
- boost asio io_service与 strand 分析
- 【Boost】boost库asio详解3——io_service作为work pool