asio笔记

asio使用笔记

编译

asio官网:
http://think-async.com/
下载页面:
http://think-async.com/Asio/Download
点击“Download”,跳转sourceforge.net,asio有boost_asio和asio版本之分,一定要区分。
最新版本为asio-1.12.1。
下载asio-1.12.1.tar.bz2:

1
https://sourceforge.net/projects/asio/files/asio/1.12.1%20%28Stable%29/asio-1.12.1.tar.bz2/download

解压:

1
tar xvf asio-1.12.1.tar.bz2 

得到asio-1.12.1文件夹,里面的include即为需要使用的头文件所在目录。为方便使用,可以整理所有头文件到一个asio目录。

使用:
参考asio自带的例子,注意,最好使用example的c++11示例。

使用笔记

一些问题及解决

使用async_read_some等待读取,但对端结束了,这里再读,就会出错,变成Bad file descriptor,错误号为9。疑问:客户端关闭,一定是返回9么?

函数及文件

endpoint的port、address在basic_endpoint.hpp中定义。另外,还有获取协议版本(v4还是v6)的protocol、data、size。

error_code类,在error_code.hpp中定义。提供int value() const、std::string message() const
错误码在error.h中定义,使用ASIO_SOCKET_ERROR、ASIO_WIN_OR_POSIX、ASIO_NATIVE_ERROR这些宏,将系统(win或linux)级别错误码转一道。如would_block实际是EWOULDBLOCK。但asio也做了扩展,因此,错误码分类有:basic_errors、netdb_errors、addrinfo_errors、misc_errors,这些都是枚举类型,在代码中可直接使用,注意,try_again和would_block在Linux下测试的值都是11。

一些接口说明

重要说明,非boost版本的asio只有hpp,因此,最好的方法是直接看源码。
获取远端的IP和端口:

1
2
3
4
5
asio::error_code ec;
// 使用带ec版本,是为了防止对端断开连接但又获取对端信息时抛出异常
asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
std::string ip = endpoint.address().to_string() + ":"
+ int2str(endpoint.port());

其中socket是tcp::socket或udp::socket的变量。

m_acceptor.bind(endpoint, ec);

有的函数没有获取错误码,会抛出异常(要么自己catch,要么系统抛出,然后程序崩溃),例如bind,有2个函数,如下:

1
2
3
4
5
6
void bind(const endpoint_type& endpoint)
{
asio::error_code ec;
this->get_service().bind(this->get_implementation(), endpoint, ec);
asio::detail::throw_error(ec, "bind");
}

获取错误码,并且不抛出异常的实现:

1
2
3
4
5
6
ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,
asio::error_code& ec)
{
this->get_service().bind(this->get_implementation(), endpoint, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

shutdown函数实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
void shutdown(shutdown_type what)
{
asio::error_code ec;
this->get_service().shutdown(this->get_implementation(), what, ec);
asio::detail::throw_error(ec, "shutdown");
}

ASIO_SYNC_OP_VOID shutdown(shutdown_type what,
asio::error_code& ec)
{
this->get_service().shutdown(this->get_implementation(), what, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

close函数:

1
2
3
4
5
6
7
8
9
10
11
12
void close()
{
asio::error_code ec;
this->get_service().close(this->get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}

ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
this->get_service().close(this->get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

常用函数列表

连接:

1
2
3
void connect(const endpoint_type& peer_endpoint)
ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint,
asio::error_code& ec)

绑定:

1
2
3
void bind(const endpoint_type& endpoint)
ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,
asio::error_code& ec)

打开:

1
2
3
void open(const protocol_type& protocol = protocol_type())
ASIO_SYNC_OP_VOID open(const protocol_type& protocol,
asio::error_code& ec)

关闭:

1
2
3
4
5
6
void close()
ASIO_SYNC_OP_VOID close(asio::error_code& ec)

void shutdown(shutdown_type what)
ASIO_SYNC_OP_VOID shutdown(shutdown_type what,
asio::error_code& ec)

获取对端IP信息:

1
2
endpoint_type remote_endpoint() const
endpoint_type remote_endpoint(asio::error_code& ec) const

获取本地IP信息:

1
2
3
endpoint_type local_endpoint() const
endpoint_type local_endpoint(asio::error_code& ec) const

取消:

1
2
void cancel()
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)