《C++游戏服务器开发入门到掌握》boost库中的网络库asio

本文介绍了C++游戏服务器开发中使用boost库的Asio网络库,讲解了Asio库的选择原因、主要作用、可移植性和效率。详细探讨了编程模型、异步编程、事件驱动模型,以及Asio在网络编程中的应用,如时间服务器和Echo服务器的实现。此外,还涉及到了消息协议设计,包括JSON和protobuf的使用。
摘要由CSDN通过智能技术生成

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++编译优化: 可以加参数O1O2O3,数字越大优化程度越高。推荐使用O2O3反而会劣化)。
  • strand_wrap(): 用来处理多线程下同时触发事件,使用同一变量的情况。使用方法:timer.async_wait中的回调函数用它包裹起来。
printer(boost:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值