boost.asio包装类st_asio_wrapper开发教程(2015.11.6更新)(三)

如果你偶然浏览到这里,请先看  boost.asio包装类st_asio_wrapper开发教程(一)
源代码及例程下载地址:
git: https://github.com/youngwolf-project/st_asio_wrapper/,另外,我的资源里面也有下载,但不是最新的。
QQ交流群:198941541

七:自定义数据结构支持
当st_asio_wrapper server与其它客户端、或者st_asio_wrapper client与其它服务端通信时,需要自定义消息结构(除非协议刚好跟默认的”2字节包长加消息内容“一样),具体如下(接收):
        1.从i_packer和i_unpacker继承,生成自己的打包解包器;
        2.调用inner_packer()和inner_unpacker()修改打包解包器;
        3.打包解包器应该要支持原始消息的打包(此时只做数据拷贝,不添加任何数据),如果考虑通用性的话。pack_msg接口的最后一个参数用于表达是否是打原始消息包(即,pack_msg是从send_msg还是从send_native_msg调用的);
        4.接收缓存必须放在解包器之内,当收到数据时,st_asio_wrapper会调用解包器的parse_msg接口,解包器应在这里面解包,并将结果通过msg_can参数返回出去;
        5.调用parse_msg之后,st_asio_wrapper马上开始下一次数据接收,此时会调用解包器的prepare_next_recv接口,这个接口负责返回一个缓存(boost 的mutable_buffers_1对象);
        6.重写completion_condition接口,这个接口用于判断什么时候可以解析消息了(即调用parse_msg),显然,至少收到一条完整的消息之后,就可以解析了;返回0代表可以解析消息了,返回其它值代表至少还需要多少字节,才能解析;这些说起来很抽象,大家看一下默认的解包器的实现就清楚了。

发送:
        1.如果你只是发送自定义数据结构,则默认st_asio_wrapper已经实现了,就是调用send_native_msg接口来发送消息,前提是,你在调用之前,数据已经组装打包好了;
        2.自定义数据结构仍然在on_msg和on_msg_handle里面接收处理消息;

        好的消息结构应该是 包头 + 长度 + 数据,其中包头可以没有,如果每一个消息的长度都是定长的,则也可以没有长度,但不要包头和长度全都没有。为什么这是好的消息结构呢,因为这样可以减少boost.asio的回调次数,也就提高了执行效率。

        一但使用自定义数据结构,二次开发者不得不自己处理粘包,分包,解包,数据缓存等工作,也就是实现自己的打包解包器。关于打包解包器的更多信息,请参考st_asio_wrapper自带的packer和unpacker。

八:ipv6支持
        st_asio_wrapper支持ipv6,demo里面有代码演示(注释状态,去掉注释开启ipv6,注意服务端和客户端都得开启),服务端我们往往不指定ip,那么st_asio_wrapper就推导不出来ip协议的版本来,此时可以通过定义DEFAULT_IP_VERSION宏来指定版本,具体请参看 教程一。

九:发送接收消息缓存,以st_tcp_socket为例,st_udp_socket同理
        这两个缓存与unpacker里面的缓存概念不一样,unpacker的缓存是boost.asio使用的最原始的缓存,且一般应该是固定大小的,st_tcp_socket的发送接收消息缓存里面保存的都是消息,可以直接取出来使用而不需要解包的,其大小不定,但有一个最大条数,具体参看 教程一。
        发送缓存为什么需要,我想不用解释了吧(如果在send_msg中,不缓存消息,而是直接投递async_write会怎样呢?这样的确是不需要发送缓存了,但多次的async_write投递,会造成包乱序,这几乎是无法解决并且不可容忍的问题,而且投递的async_write数量也是不定的,内存占用不可控,所以st_tcp_socket采用了发送缓存,每次只投递一个async_write,等到发送成功之后,再投递下一次)。对于接收消息缓存,其实是可以不要的,重写on_msg,在里面处理消息即可,但这样带来一个问题,st_tcp_socket需要在on_msg之后才投递下一次async_read(同样为了解决乱序问题),这样消息处理就阻塞了消息接收;为此,采用了接收消息缓存,当收到消息的时候,直接放在缓存里,再在另外的线程中,回调on_msg_handler,达到了消息处理与消息接收异步的目的。
        如果你不想使用接收消息缓存,则重写on_msg,要么马上处理消息,要么将消息拷贝到你自己的缓存中,由你自己的调度线程去分发消息,最后返回true;对于马上处理消息的情况,一定注意要快速,否则会阻塞下次消息的接收。
        如果on_msg返回false(默认返回true),消息将进入st_tcp_socket的接收消息缓存,并在适当的时候,回调on_msg_handle,你可以在这里面处理消息,并且不会阻塞下次消息的接收(除非所有IO线程都被阻塞,那说明你的线程不够了;IO线程数量请参看第一篇教程中的ST_SERVICE_THREAD_NUM宏)。

        st_asio_wrapper保证消息按照顺序发送、接收和分发(on_msg 和 on_msg_handle),所以你完全不用担心消息乱序的问题。当然,顺序接收得说两句,接收端是不知道发送端的顺序的,所以顺序接收要建立在顺序发送的基础之上。

boost.asio包装类st_asio_wrapper开发教程(四)

你可能感兴趣的:(boost.asio包装类st_asio_wrapper开发教程(2015.11.6更新)(三))