专门一篇来记录纠结的过程:啥都不懂,异步,回调…

原来我搞这么久,程序是跑起来了,但是真的不知道server段用了异步回调操作之后,整个流程到底是怎样的,前天一步步地调了之后,才发现这些过程自己完全不知道…所以没办法了,现在不搞懂的话之后代码拓展了就更不可收拾了,利用这个周末好好恶补下吧,今晚搞不通就不睡觉了,哎!

先统一放几个,我认为对于我所困惑的问题解释得比较到点的博文链接吧,谢谢这些朋友:

http://blog.csdn.net/henreash/article/details/7469707

http://blog.csdn.net/zhuky/article/details/5364685

http://cpp.ezbty.org/content/science_doc/%E4%BD%BF%E7%94%A8boostasio%E7%BC%96%E5%86%99%E9%80%9A%E4%BF%A1%E7%A8%8B%E5%BA%8F#ASIO-4

 

吃完饭回来,散个步,去了趟85度C买了个明天的早餐,忽然豁然开朗了!原来异步回调是这么个回事!!!!!!!!!

也感谢上面那给出链接的三篇博文吧,多多少少都是从别人的经验上自己摸索出来的,纵使别人讲得不一定符合自己的思考逻辑,但是我今晚还是选择了椰汁香奶包来当明天早餐,呵呵,一成不变

 

首先是io service的run的方法吧,其他人也说得够多了,它就是充当一个打通你的程序跟操作系统的读写通道的这么一个存在,你要将它run起来,否则你之后的读写操作都是不起作用的;

然后就是几个需要注意的问题,其实官方文档上也有写到,比如read和write里面的socket和buffer,都是要保证他们在这个操作的整个生命周期里面是保持存在的,因为这个不是复制的,还包括那个tcp的connection的socket之类的,这些我觉得还好,也不用当心什么,毕竟例程也已经做了一个很好的榜样了,用智能指针包装下成为自己的类成员,然后只有对象不析构的话就没问题了,fine,这单pass了

 

接下来就是重点了,其实我面向的就是手上这份,改过的,跑通了的但是原理没搞通的在server2的基础上做改进的,无非就是给client端加些线程,让他们同时去访问server,然后在输出信息的过程中,意思是server端输出信息的过程中,我就觉得怎么那么诡异呢?输出信息的顺序到底是哪个先哪个后呢?那些async的方法然后后面加个bind的形式如此简洁明了到底在他们的背后藏了多少惊人的秘密呢?!哎,咖啡喝完了看来又要在天猫超市买了,这次还是回归雀巢吧,下面就说下我所理解的,至少按照这个思路能完全很好地解释在server的cout里面输出信息的顺序:

 

每个诸如async_***(par1, bind(&handler,par2,boost::system::error_Code))这样的函数,都是一些异步回调函数,异步就是从它名字看得出来了吧,回调的话bind里面的那个handler就是回调函数,我自己觉得这样称呼最好:那些是在某些特定条件满足下才被触发的函数,啥时候被调用不着你自己去考虑,你给出条件给出变量,系统帮你完成

然后其实每一个诸如上面形式的函数,它都是第一:干完我自己这个函数本来要干的事情,比如async_read(socket,buffer,bind(&handler_read,***)),从socket里面读出内容到buffer里面去,ok,足够了,这个就是它自己这个函数本身所要完成的工作,然后第二:把这个handle read这个回调函数加入到一个queue队列当中,隐形的,看不到的,系统维护的,反正听说那个io services还是什么的会一直去查询不断地执行还未完成也就是未返回的哪些回调函数的。第三:适当的时候,系统会按照队列里面的顺序,一一执行,ok,适当的时候,是不是说得很隐晦很蛋疼呢?下面展开下,用我现在手上修改过后的server2的例程:

首先在main函数里面,server初始化的下一句,就是Io service的run,那么在server的初始化过程中,会启动一个start accept的函数,这个函数当中,有这么一句:

acceptor_.async_accept(new_connection_->socket(), boost::bind(&server::handle_accept, this, boost::asio::placeholders::error));

这个就是开通这个socket端口在监听请求,然后把handle_accept这个回调函数放到queue里面去,然后就结束了这个函数,其实最后面那个error的那个参数,每个bind的回调函数都会有的,就是由这个创建它的函数传给它的,意思是”告诉回调函数,创建你的那个家伙在结束执行时时一个怎样的状态“,然后这个start accept就执行完了,回到main函数去,执行io_service.run(),然后这个run了之后,io services就相当于阻塞在那里了,因为我试过在下面加一句cout是不会打印出来的,嗯嗯,它阻塞的时候在干什么事情呢?其实就是去queue里面找函数去执行去啦!

ok,那肯定就是去执行handle accept了吧,这个也好说,因为那边客户端已经启动了,然后这边就会接受到请求,然后在handle accept的层层调用之后,会在connection的start方面里面,又出现一个异步回调函数:

void connection::start()
{
    cout << "Now the connection triggers the start method...\n";
    Sleep(20000);

    socket_.async_read_some(boost::asio::buffer(buffer_),
        boost::bind(&connection::handle_read, shared_from_this(),
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));

    cout << "Connection::start ---  finish aync_read_some...\n";
    cout << "Let's find out what's in the buffer now...\n";
    string tmp_string(buffer_.begin(), buffer_.end());
    cout << tmp_string;
}

额,其实那些什么睡眠和输出都是我自己为了吃透这个源码的时候添加的,核心是哪一句大家一下就看到了吧,虽然也不知道有没有人来看,不过今晚实验室的暖气还是显得很干燥,哎

我为什么要输出下面那个呢?其实我就是想验证这种函数在执行了它之后,到底是执行了什么,其实就是我想看看buffer里面到底有没有读东西进来,ok,有的,然后就把那个handle read放到queue里面,这个start函数就执行完了,然后就返回到handle accept这个函数里面了,呵呵,其实保持整个server端是一个不断地监听的状态的一个奥秘就在于,handleaccept这个家伙的最后一行就是又再一次调用start accept,相当于两个函数互相调用,只不过这里巧妙在于是一个异步回调的函数,所以可以做很多其他的工作

 

ok,回到了start accept里面,上面已经分析过了,这个时候,又把一个handle accept的回调函数放到queue里面了,然后一个需要注意的小小的关键点来了,执行完了start accept之后,没东西可以往下走了吧?呵呵,这个时候就是上面的称之为关键的时候了,也就是这个流程走到尾了,才会去检查queue里面的东西的,我们queue里面有两个家伙没错吧,当然就是先执行handle read咯,那么handle read这个函数在server端就是设计成一股脑地把reply都搞定了的,然后,在这里面,它又会放一个异步回调函数进去:

                boost::asio::async_write(socket_, reply_.to_buffers(),
                    boost::bind(&connection::handle_write, shared_from_this(), 
                    boost::asio::placeholders::error));

然后因为客户端是同步的,所以在这个函数写过了之后,那边因为是阻塞在那里等待的socket里面出现内容的,所有那边就马上读到了,然后放一个handle write到queue里面,然后handle read流程走完了之后,就去queue拿刚才那个handle request出来搞搞 ,因为又接受到新的请求了的,所有就按照流程走下去,然后搞完这条流程,handle write就被执行了,里面主要是做一些stop掉那个connection的工作,然后这样子,才算是把第一个请求的所有的相关流程走了一次,那么后面的就不累述了

 

哎!终于搞定!还真挺担心自己搞不懂又下了毒誓说搞不定就不睡觉的,看来今晚还是可以睡觉了,不过今晚还有一份一万字的报告要写,来吧!

posted @ 2013-12-01 19:42  Allen_Tung  阅读(1324)  评论(0编辑  收藏  举报