84、01
- 服务器编程一般的思路: 1、选择一个平台、熟悉API、构建框架;2、找一个成熟的框架,学习它。通过学习它掌握服务器编程方面的知识。
- 成熟的框架有很多,这里选用Asio网络库原因有:简单方便;作者写的代码比较规范;可能进入下一代的C++标准库中。
- 主要作用: 主要用在服务端编程中处理服务器和客户端的socket。不限于此,类似于文件、时间都可以处理。
- 可移植性好: 在windows下可能使用iocp,在linux下可能使用epoll,在bsd下可能使用kqueue。
- 可扩展性高: 可以自己进行扩展。
- 效率高: 有的库虽然可移植,但是效率可能发生变化。
- 接口相近: API与原生的SocketsAPI基本一致。易于理解和使用。
- 易于使用: 接口明确清晰(不会有二义性)。但是过于相近。
- 基于更多的抽象: 不管是TCP还是UDP,提供的接口是一致的。不是基于网络,基于文件(流)的也可以套用Asio。
- 两种方式: 1、同步方式(最简单);2、异步方式(最常用)。
85、编程模型
- 基于事件驱动的编程模型: Reactor模型(Lighttpd、libevent、libev、poco),Proactor模型(Asio、Iocp)。
89、例子详解01
boost::asio::io_service io;用于调用系统函数,这种调用操作分为阻塞和非阻塞。- timer t(io, 5s); 添加监听事件;
- t.wait();
- t.async_wait(); 绑定回调函数。
- io.run(): 相当于一个while循环,返回退出条件有两种:1、调用io本身的stop函数;2、消息池里没有注册函数了(所有的事件全部处理完毕)。
问题1: 实现非阻塞中的阻塞。改动例子中的代码,要求先执行2秒倒计时,2秒倒计时结束后再执行5秒倒计时。
问题2: boost库中的timer只能执行一次,自己实现一个timer类:1、可以执行多次或者无限次;2、可以取消掉;3、可以中途延时(暂停)。
90、例子详解02,捎带C++黑暗面
- lambda取代bind:
io.async_wait传入一个函数(可调用的模板参数),需要带参数怎么办?以前C++03的做法是传入bind,实际就是std::function也是来自boost::function。现在可以用lambda代替,看起来简单便于理解,并且可以是inline(编译时展开的)。 - auto作为lambda的形参,要在C++14版本才支持。修改方式:1、不用auto,写上正确类型;2、修改编译文件makefile,指定C++14。
- expires_at(): 不传参返回timer结束时间,传参则设置timer结束时间。
- 生命周期注意事项: 在
io.run()中绑定的参数,要确保生命周期比run要长,否则会出问题。 - 奇怪了: 想要说明C++的黑暗面,即指针变成野指针了,但是数据结构还是没有变,行为看起来是正确的。于是老师最后5分钟快速举例子,想要弄一个出错的,但是好像没有成功,因为打印出来的
012341234234344我觉得是正确的。老师却说0000011111222223333344444才对。
91、例子详解03 - lambda的本质
- 语法糖: 没有什么新东西,只是编译器完成了部分工作。
- 本质: 在外部定义了一个类,重载了
()操作符,如果有参就加参,有外部引用就加成员变量。 - 解决: 上节课遗留的问题是,打印出来的地址都是一样的。(老师纠正后的数字打印,验证了我的想法是没有错的)。通过传入智能指针的方式来延长指针的生命周期,修正了错误。
- 新问题: 万一就是不想让智能指针的生命周期那么长呢?二一个就是将智能指针作为接口函数,可能会强迫调用者也要使用智能指针。(这里asio编程没有问题,大多用的智能指针,但别的地方可能有问题,老师个人观点。)
92、06
- 如何用bind绑定成员函数: 官方文档介绍的是用bind方法。
- 奇怪: 绑定成员函数的时候,貌似不用传入
boost::system::error_code的引用参数。第一个参数为成员函数地址&printer::print,第二个参数为调用者this。用lambda的时候还是需要传入那个参数。 - 解答: boost库bind函数在使用时,实际有很多默认的参数,所以可以忽略掉。
- 反复强调: 绑定函数中使用到的参数(指针),生命周期一定要大于整个事件。服务器编程回调的Bug,很多都是参数失效造成的。
- 疑问: timer析构的时候,本身会调用cancel,这个可以理解。但是为什么会在printer的构造函数中就会发出error为
boost::asio::error::operation_aborted呢?
93、07 io_service在多线程下如何使用
- 通常设计: 主线程跑逻辑、额外线程跑io_service(收发玩家消息或者监听timer)。
int main(int argc, char** argv) {
boost::asio::io_service io;
printer p(io);
std::thread t([&io] {
io.run(); });
t.join();
system("pause");
return EXIT_SUCCESS;
}
- -lpthread: 多线程编程时,在编译时加
-lpthread,来连接这个库。linux和bsd操作系统下标准的实现。 - g++编译优化: 可以加参数
O1、O2、O3,数字越大优化程度越高。推荐使用O2(O3反而会劣化)。 - strand_wrap(): 用来处理多线程下同时触发事件,使用同一变量的情况。使用方法:timer.async_wait中的回调函数用它包裹起来。
printer(boost:
本文介绍了C++游戏服务器开发中使用boost库的Asio网络库,讲解了Asio库的选择原因、主要作用、可移植性和效率。详细探讨了编程模型、异步编程、事件驱动模型,以及Asio在网络编程中的应用,如时间服务器和Echo服务器的实现。此外,还涉及到了消息协议设计,包括JSON和protobuf的使用。
最低0.47元/天 解锁文章

1万+

被折叠的 条评论
为什么被折叠?



