您的位置:首页 > 编程语言 > C语言/C++

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  socket c语言 boost