背景
在2016年的时候,自己做的一个游戏项目英语杀(C++/Qt)游戏后台使用了很普通的socket连接方式:一个socket+一个线程模式,这种模式连接几百个客户端应该没问题,成千上万个就不行了。虽然当时项目还用不到,但抱着技术第一的态度在网上搜了很久的文章,最终确定了学习和开发IOCP来解决高并发的问题(当初并不知道有libevent、libuv这些库的存在,所以才入了坑),前前后后开发和维护了近4年,看了相当多的IOCP源码(古今中外都有),也解决了非常多的问题和坑,目前项目的生产环境很稳定,阿里云最低配的云主机(1核1G)运行无压力,现就开发时遇到的所有问题统一做一个分析和解答系列文章。
简介
一、后台框架:
1、IOCP内核库
库使用VC6开发(因为编译和运行快,文件小,依赖少),整体就是一个dll,主要封装了IOCP的核心代码,提供了非常多的C函数供使用。
2、Qt封装IOCP的库
这是第一层封装,将Dll库封装为一个类,完成了所有导出函数、句柄的封装,和IOCP库的载入和卸载。
3、Server封装
这是第二层封装,主要加入和解决了以下问题:
1、TCP数据的粘包处理,定义了数据的类型、简单验证、加密等。
2、随机数的同步。
3、定义了用户、群、群主的数据结构和功能,完善了群的管理(包括查找、进入和离开群,创建和解散群,群主的更换和T人,群数据发送和用户信息同步等)。
4、GameServer封装
这主要实现了业务逻辑,也做了其他一些亮点功能,比如多线程完成日志的记录、数据库的查询等。
二、内核库介绍
1、心跳机制
windows系统内核的TCP协议里并没有实现心跳,导致客户端异常断开后无法检测到,所以自己实现了一套写在了核心代码里。
2、自定义程度高
导出的函数中有很多set开头的函数,让开发者自定义某些IOCP的运行机制。
3、回调函数
因为库接口是C,所以只能使用回调函数的机制来运行开发者代码,缺点是使用难度有所提高,但我封装的每一层都有回调函数的示例,参照着写即可。
4、池
内核主要有两个池:SocketContext池和IOContext池,运行起来后不会频繁的new和delete,而是通过池来分配和回收,大大降低了new和delete的开销。
5、收发各使用一个IOContext
Send维护一个发送队列,且发送一个包的最大长度是8192左右,内核发送大数据时按照这个包自动拆分包,且完善了发送错误处理。
6、锁
把这个单独提出来是因为之前的代码里用到了至少3个锁,分别用来保护两个池和一个SocketClient队列,最近我把内核重新进行了大的重构,把这三个锁都去掉了,实现了无锁IOCP,后期的文章里会慢慢进行说明。
7、其他
内核还处理了各式各样的异常和错误。目前就想起来这么多,除了IOCP核心代码是用小猪的更改而来(修改达到70%左右吧),其他的全部都是自己设计和编写的,后期也会进行开源。顺带说一句,用C++开发全栈真是活的不耐烦了。。。
原理和参考
原理方面的东西我就不赘述了,我是直接从最low模型到IOCP模型的,中间还有其他异步模型,因为都不如IOCP我就直接跳过,这里只讲一些小猪的代码里没提到的坑。关于其他异步模型和IOCP的原理、简单实现只需参考小猪的一篇文章就行:
完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三
我的git地址(英语杀):https://gitee.com/leamus
IOCP的git地址:https://gitee.com/leamus/iocp_leamus
讨论QQ群:950384383