* 常见流程分析之一(Tcp异步连接)

我们用一个简单的demo分析Tcp异步连接的流程:

 #include <iostream>
#include <boost/asio.hpp> // 异步连接回调函数
void on_connect(boost::system::error_code ec)
{
if (ec) // 连接失败, 输出错误码
std::cout << "async connect error:" << ec.message() << std::endl;
else // 连接成功
std::cout << "async connect ok!" << std::endl;
} int main()
{
boost::asio::io_service ios; // 创建io_service对象
boost::asio::ip::tcp::endpoint addr(
boost::asio::ip::address::from_string("127.0.0.1"), ); // server端地址
boost::asio::ip::tcp::socket conn_socket(ios); // 创建tcp协议的socket对象
conn_socket.async_connect(addr, &on_connect); // 发起异步连接请求
ios.run(); // 调用io_service::run, 等待异步操作结果 std::cin.get();
return ;
}

这段代码中的异步连接请求在asio源码中的序列图如下:

其中,basic_socket是个模板类,tcp协议中的socket的定义如下:
            typedef basic_socket<tcp> socket;

reactor的定义如下:
      #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
            typedef class null_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_IOCP)
            typedef class select_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_EPOLL)
            typedef class epoll_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_KQUEUE)
            typedef class kqueue_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_DEV_POLL)
            typedef class dev_poll_reactor reactor;
      #else
            typedef class select_reactor reactor;
      #endif

在这个序列图中最值得注意的一点是:在windows平台下,异步连接请求不是由Iocp处理的,而是由select模型处理的,这是与异步读写数据最大的不同之处。

* 常见流程分析之二(Tcp异步接受连接)

我们用一个简单的demo分析Tcp异步连接的流程:

 #include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp> // 异步连接回调函数
void on_accept(boost::system::error_code ec, boost::asio::ip::tcp::socket * socket_ptr)
{
if (ec) // 连接失败, 输出错误码
std::cout << "async accept error:" << ec.message() << std::endl;
else // 连接成功
std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl; // 断开连接, 释放资源.
socket_ptr->close(), delete socket_ptr;
} int main()
{
boost::asio::io_service ios; // 创建io_service对象
boost::asio::ip::tcp::endpoint addr(
boost::asio::ip::address::from_string("0.0.0.0"), ); // server端地址
boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // 创建acceptor对象
boost::asio::ip::tcp::socket * socket_ptr = new boost::asio::ip::tcp::socket(ios);
acceptor.async_accept(*socket_ptr
, boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // 调用异步accept请求
ios.run(); // 调用io_service::run, 等待异步操作结果 std::cin.get();
return ;
}

这段代码中的异步连接请求在asio源码中的序列图如下:

* 常见流程分析之三(Tcp异步读写数据)

我们依然以上一节的例子为基础,扩展一个简单的demo分析Tcp异步读写数据的流程:

 #include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/array.hpp> typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
typedef boost::array<char, > buffer_t;
typedef boost::shared_ptr<buffer_t> buffer_ptr_t; // 异步读数据回调函数
void on_read(boost::system::error_code ec
, std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
{
if (ec)
std::cout << "async write error:" << ec.message() << std::endl;
else
{
std::cout << "async read size:" << len;
std::cout << " info:" << std::string((char*)buffer_ptr->begin(), len) << std::endl; // auto release socket and buffer.
}
} // 异步写数据回调函数
void on_write(boost::system::error_code ec
, std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
{
if (ec)
std::cout << "async write error:" << ec.message() << std::endl;
else
{
std::cout << "async write size:" << len << std::endl;
socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
, boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
, socket_ptr, buffer_ptr));
}
} // 异步连接回调函数
void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
{
if (ec) // 连接失败, 输出错误码
{
std::cout << "async accept error:" << ec.message() << std::endl;
}
else // 连接成功
{
std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
buffer_ptr_t buffer_ptr(new buffer_t);
strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
, boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
, socket_ptr, buffer_ptr));
}
} int main()
{
boost::asio::io_service ios; // 创建io_service对象
boost::asio::ip::tcp::endpoint addr(
boost::asio::ip::address::from_string("0.0.0.0"), ); // server端地址
boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // 创建acceptor对象
socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
acceptor.async_accept(*socket_ptr
, boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // 调用异步accept请求
ios.run(); // 调用io_service::run, 等待异步操作结果 std::cout << "press enter key...";
std::cin.get();
return ;
}

这段代码中的异步连接请求在asio源码中的序列图如下:

* 常见流程分析之四(Tcp强制关闭连接)

我们依然以上一节的例子为基础,扩展一个简单的demo分析Tcp强制关闭连接的流程:

 #include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/array.hpp> typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
typedef boost::array<char, > buffer_t;
typedef boost::shared_ptr<buffer_t> buffer_ptr_t; // 异步读数据回调函数
void on_read(boost::system::error_code ec
, std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
{
if (ec) // 连接失败, 输出错误码
{
std::cout << "async read error:" << ec.message() << std::endl;
}
} // 异步写数据回调函数
void on_write(boost::system::error_code ec
, std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
{
if (ec) // 连接失败, 输出错误码
{
std::cout << "async write error:" << ec.message() << std::endl;
}
} // 异步连接回调函数
void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
{
if (ec) // 连接失败, 输出错误码
{
std::cout << "async accept error:" << ec.message() << std::endl;
}
else // 连接成功
{
std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl; {
buffer_ptr_t buffer_ptr(new buffer_t);
strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
, boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
, socket_ptr, buffer_ptr));
} {
buffer_ptr_t buffer_ptr(new buffer_t);
socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
, boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
, socket_ptr, buffer_ptr));
} /// 强制关闭连接
socket_ptr->close(ec);
if (ec)
std::cout << "close error:" << ec.message() << std::endl;
}
} int main()
{
boost::asio::io_service ios; // 创建io_service对象
boost::asio::ip::tcp::endpoint addr(
boost::asio::ip::address::from_string("0.0.0.0"), ); // server端地址
boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // 创建acceptor对象
socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
acceptor.async_accept(*socket_ptr
, boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // 调用异步accept请求
socket_ptr.reset();
ios.run(); // 调用io_service::run, 等待异步操作结果 std::cout << "press enter key...";
std::cin.get();
return ;
}

这个例子中,接受到客户端的连接后,立即发起异步读请求和异步写请求,然后立即强制关闭socket。

其中,强制关闭socket的请求在asio源码中的序列图如下:

* 常见流程分析之五(Tcp优雅地关闭连接)

我们依然以第三节的例子为基础,扩展一个简单的demo分析Tcp优雅地关闭连接的流程:

 #include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/array.hpp> typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
typedef boost::array<char, > buffer_t;
typedef boost::shared_ptr<buffer_t> buffer_ptr_t; // 异步读数据回调函数
void on_read(boost::system::error_code ec
, std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
{
static int si = ;
if (ec) // 连接失败, 输出错误码
{
std::cout << "async read(" << si++ << ") error:" << ec.message() << std::endl;
socket_ptr->shutdown(boost::asio::socket_base::shutdown_receive, ec);
socket_ptr->close(ec);
if (ec)
std::cout << "close error:" << ec.message() << std::endl;
}
else
{
std::cout << "read(" << si++ << ") len:" << len << std::endl; socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
, boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
, socket_ptr, buffer_ptr));
}
} // 异步写数据回调函数
void on_write(boost::system::error_code ec
, std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
{
if (ec) // 连接失败, 输出错误码
{
std::cout << "async write error:" << ec.message() << std::endl;
}
else
{
/// 优雅地关闭连接
socket_ptr->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
if (ec)
std::cout << "shutdown send error:" << ec.message() << std::endl;
}
} // 异步连接回调函数
void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
{
if (ec) // 连接失败, 输出错误码
{
std::cout << "async accept error:" << ec.message() << std::endl;
}
else // 连接成功
{
std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl; {
buffer_ptr_t buffer_ptr(new buffer_t);
socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
, boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
, socket_ptr, buffer_ptr));
} {
buffer_ptr_t buffer_ptr(new buffer_t);
strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
, boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
, socket_ptr, buffer_ptr));
}
}
} int main()
{
boost::asio::io_service ios; // 创建io_service对象
boost::asio::ip::tcp::endpoint addr(
boost::asio::ip::address::from_string("0.0.0.0"), ); // server端地址
boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // 创建acceptor对象
socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
acceptor.async_accept(*socket_ptr
, boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // 调用异步accept请求
socket_ptr.reset();
ios.run(); // 调用io_service::run, 等待异步操作结果 std::cout << "press enter key...";
std::cin.get();
return ;
}

在这个例子中,接收到客户端的连接并向客户端发送数据以后,先关闭socket的发送通道,然后等待socket接收缓冲区中的数据全部read出来以后,再关闭socket的接收通道。此时,socket的接收和发送通道均以关闭,任何进程都无法使用此socket收发数据,但其所占用的系统资源并未释放,底层发送缓冲区中的数据也不保证已全部发出,需要在此之后执行close操作以便释放系统资源。
      若在释放系统资源前希望底层发送缓冲区中的数据依然可以发出,则需在socket的linger属性中设置一个等待时间,以便有时间等待发送缓冲区中的数据发送完毕。但linger中的值绝对不是越大越好,这是因为其原理是操作系统帮忙保留socket的资源以等待其发送缓冲区中的数据发送完毕,如果远端socket的一直未能接收数据便会导致本地socket一直等待下去,这对系统资源是极大的浪费。因此,在需要处理大量连接的服务端,linger的值一定不可过大。

由于本文会实时根据读者反馈的宝贵意见更新,为防其他读者看到过时的文章,因此本系列专题谢绝转载!

boost.asio源码剖析(三) ---- 流程分析的更多相关文章

  1. boost.asio源码剖析(一) ---- 前 言

    * 前言 源码之前,了无秘密.                                                       ——侯捷 Boost库是一个可移植.提供源代码的C++库,作 ...

  2. boost.asio源码剖析

    一. 前 言二. 架构浅析三. 流程分析     * 常见流程分析之一(Tcp异步连接)      * 常见流程分析之二(Tcp异步接受连接)      * 常见流程分析之三(Tcp异步读写数据)   ...

  3. boost.asio源码剖析(五) ---- 泛型与面向对象的完美结合

    有人说C++是带类的C:有人说C++是面向对象编程语言:有人说C++是面向过程与面向对象结合的语言.类似的评论网上有很多,虽然正确,却片面,是断章取义之言. C++是实践的产物,C++并没有为了成为某 ...

  4. boost.asio源码剖析(四) ---- asio中的泛型概念(concepts)

    * Protocol(通信协议) Protocol,是asio在网络编程方面最重要的一个concept.在第一章中的levelX类图中可以看到,所有提供网络相关功能的服务和I/O对象都需要Protoc ...

  5. boost.asio源码剖析(二) ---- 架构浅析

    * 架构浅析 先来看一下asio的0层的组件图.                     (图1.0) io_object是I/O对象的集合,其中包含大家所熟悉的socket.deadline_tim ...

  6. boost.asio源码阅读(2) - task_io_service

    1.0 task_io_service 在boost.asio源码阅读(1)中,代码已经查看到task_io_service中. 具体的操作调用void task_io_service::init_t ...

  7. Netty 源码学习——客户端流程分析

    Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...

  8. Faiss源码剖析:类结构分析

    摘要:在下文中,我将尝试通过Faiss源码中各种类结构的设计来梳理Faiss中的各种概念以及它们之间的关系. 本文分享自华为云社区<Faiss源码剖析(一):类结构分析>,原文作者:HW0 ...

  9. jdk源码剖析三:锁Synchronized

    一.Synchronized作用 (1)确保线程互斥的访问同步代码 (2)保证共享变量的修改能够及时可见 (3)有效解决重排序问题.(Synchronized同步中的代码JVM不会轻易优化重排序) 二 ...

随机推荐

  1. java线程(上)Thread和Runnable的区别

    首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程. 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈 ...

  2. 算法笔记_171:历届试题 小朋友排队(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 n 个小朋友站成一排.现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友. 每个小朋友都有一个不高兴的程度.开始的 ...

  3. 用JavaScript 来创建 mac os x 程序这样是否好

    在网上看到的文章: 用 JavaScript 编写 OS X 应用 (Tyler Gaw)   这个文章的内容是不错的. 可是思路呢? 我们假设想学一种方法或工具,这样做好吗? 我看了上面的代码.假设 ...

  4. tomcat 热部署、热加载 精析

        1.前言 找了很多篇文章,没有一篇文章讲的清晰.明了,很多人只是会用,但不是能真正说明白,这年头找个懂理论的,真难! 2.热部署 原定义:tomcat处于运行状态时,能够监测webapps下的 ...

  5. 如何提高SELECT的效率

      首先避免使用in ,not in,<>,<,<=,>,>=,is null,is not null 主要搜索字段建立索引 .WHERE子句中的连接顺序 sql解 ...

  6. tomcat7.0.27的bio,nio.apr高级运行模式(转)

    一 前言 tomcat的运行模式有3种.修改他们的运行模式.3种模式的运行是否成功,可以看他的启动控制台,或者启动日志.或者登录他们的默认页面http://localhost:8080/查看其中的服务 ...

  7. eclipse新建maven工程的各种坑

    尽量按照最后强烈推荐的那篇创建maven工程.  1.jsp文件头报错 2.xml配置文件头红叉 3.Archive for required library...blabla 4.pom依赖出错 5 ...

  8. Fn键

    需求分析 我想开机禁用触摸板. 方案设计 安装驱动:比较麻烦,驱动也不一定支持开机禁用触摸板. 编程实现,让一段代码开机禁用触摸板 编程实现也分好几种方法: 使用windows API禁用触摸板,这需 ...

  9. 【LeetCode】107. Binary Tree Level Order Traversal II (2 solutions)

    Binary Tree Level Order Traversal II Given a binary tree, return the bottom-up level order traversal ...

  10. 【LeetCode】93. Restore IP Addresses

    Restore IP Addresses Given a string containing only digits, restore it by returning all possible val ...