├── .gitignore ├── README.md └── articles ├── C++必知必会的知识点 ├── C++17结构化绑定.md ├── C++必须掌握的pimpl惯用法.md ├── README.md ├── 不定参数函数实现var_arg系列的宏.md ├── 你一定要搞明白的C函数调用方式与栈原理.md ├── 利用cmake工具生成VisualStudio工程文件.md ├── 如何使用VisualStudio管理和阅读开源项目代码.md ├── 如何成为一名合格的CC++开发者?.md ├── 深入理解CC++中的指针.md ├── 用VisualStudio调试Linux程序.md └── 详解C++11中的智能指针.md ├── Memcached源码分析 ├── .DS_Store ├── 00服务器资源调整.md ├── 01初始化参数解析.md ├── 02网络监听的建立.md ├── 03网络连接建立.md ├── 04内存初始化.md ├── 05资源初始化.md ├── 06get过程.md ├── 07cas属性.md ├── 08内存池.md ├── 09连接队列.md ├── 10Hash表操作.md ├── 11LRU操作.md ├── 12set操作.md ├── 13do_item_alloc操作.md ├── 14item结构.md ├── 15Hash表扩容.md ├── 16线程交互.md ├── 17状态机.md └── README.md ├── TeamTalk源码解析 ├── .DS_Store ├── 01TeamTalk介绍.md ├── 02服务器端的程序的编译与部署.md ├── 03服务器端的程序架构介绍.md ├── 04服务器端db_proxy_server源码分析.md ├── 05服务器端msg_server源码分析.md ├── 06服务器端login_server源码分析.md ├── 07服务器端msfs源码分析.md ├── 08服务器端file_server源码分析.md ├── 09服务器端route_server源码分析.md ├── 10开放一个TeamTalk测试服务器地址和几个测试账号.md ├── 11pc客户端源码分析.md └── index.md ├── cppguide-wechat.png ├── imgs ├── .DS_Store ├── 12306-1.webp ├── 12306-10.webp ├── 12306-11.webp ├── 12306-12.jpeg ├── 12306-13.webp ├── 12306-14.webp ├── 12306-15.jpeg ├── 12306-2.webp ├── 12306-3.webp ├── 12306-4.webp ├── 12306-5.webp ├── 12306-6.webp ├── 12306-7.webp ├── 12306-8.webp ├── 12306-9.webp ├── atomic1.webp ├── bz1.png ├── bz2.webp ├── cmake1.png ├── cmake2.png ├── cmake3.png ├── cmake4.png ├── connect1.png ├── connect10.webp ├── connect11.png ├── connect12.webp ├── connect13.webp ├── connect2.webp ├── connect3.webp ├── connect4.webp ├── connect5.png ├── connect6.webp ├── connect7.webp ├── connect8.png ├── connect9.webp ├── epoll.png ├── errorsys1.png ├── game1.webp ├── game10.jpeg ├── game11.webp ├── game12.webp ├── game13.webp ├── game14.webp ├── game15.webp ├── game16.webp ├── game17.webp ├── game18.webp ├── game19.webp ├── game2.webp ├── game20.webp ├── game21.webp ├── game22.webp ├── game23.webp ├── game24.webp ├── game25.webp ├── game26.webp ├── game27.png ├── game28.png ├── game29.png ├── game3.webp ├── game30.webp ├── game31.webp ├── game32.png ├── game33.png ├── game34.png ├── game35.png ├── game36.png ├── game37.png ├── game38.png ├── game39.png ├── game4.webp ├── game40.png ├── game41.png ├── game42.webp ├── game43.webp ├── game44.webp ├── game45.webp ├── game46.webp ├── game47.webp ├── game48.webp ├── game49.png ├── game5.webp ├── game50.png ├── game51.png ├── game52.png ├── game53.webp ├── game54.webp ├── game55.jpeg ├── game56.png ├── game57.jpeg ├── game58.webp ├── game59.png ├── game6.png ├── game60.png ├── game61.webp ├── game62.png ├── game63.webp ├── game64.webp ├── game65.jpeg ├── game66.webp ├── game67.webp ├── game68.jpeg ├── game69.webp ├── game7.jpeg ├── game7.png ├── game70.webp ├── game71.jpeg ├── game72.png ├── game73.png ├── game74.webp ├── game75.png ├── game76.jpeg ├── game77.webp ├── game78.png ├── game79.png ├── game8.jpeg ├── game80.jpeg ├── game81.png ├── game82.webp ├── game83.jpeg ├── game84.png ├── game85.webp ├── game86.jpeg ├── game87.png ├── game88.webp ├── game89.jpeg ├── game9.jpeg ├── game90.png ├── game91.png ├── game92.webp ├── game93.webp ├── game94.jpeg ├── game95.webp ├── http1.webp ├── http2.webp ├── http3.webp ├── http4.webp ├── http5.webp ├── jianli1.png ├── jianli2.png ├── jianli3.png ├── jianli4.png ├── jianli5.png ├── jianli6.png ├── jianli7.png ├── jianli8.png ├── learningcpp1.png ├── learningcpp2.png ├── learningcpp3.png ├── learningcpp4.png ├── learningcpp5.png ├── learningcpp6.png ├── learningcpp7.png ├── leveldb1.png ├── leveldb10.webp ├── leveldb11.webp ├── leveldb12.webp ├── leveldb13.webp ├── leveldb14.webp ├── leveldb15.webp ├── leveldb16.webp ├── leveldb17.webp ├── leveldb18.webp ├── leveldb19.webp ├── leveldb2.webp ├── leveldb20.webp ├── leveldb3.webp ├── leveldb4.webp ├── leveldb5.webp ├── leveldb6.webp ├── leveldb7.webp ├── leveldb8.webp ├── leveldb9.webp ├── libevent1.webp ├── libevent10.webp ├── libevent11.webp ├── libevent12.webp ├── libevent2.webp ├── libevent3.webp ├── libevent4.webp ├── libevent5.webp ├── libevent6.webp ├── libevent7.webp ├── libevent8.webp ├── libevent9.webp ├── log1.png ├── lsof1.jpeg ├── lsof2.webp ├── mail1.png ├── mail2.png ├── mail3.png ├── mail4.png ├── mail5.png ├── mail6.png ├── mail7.png ├── mail8.png ├── memcached1.webp ├── memcached2.webp ├── memcached3.webp ├── memcached4.webp ├── nc1.png ├── nc2.jpeg ├── nc3.jpeg ├── netdown1.webp ├── netdown10.webp ├── netdown11.png ├── netdown12.webp ├── netdown13.png ├── netdown14.jpeg ├── netdown15.jpeg ├── netdown16.webp ├── netdown17.jpeg ├── netdown18.png ├── netdown19.jpeg ├── netdown2.webp ├── netdown20.jpeg ├── netdown21.jpeg ├── netdown22.jpeg ├── netdown23.png ├── netdown24.webp ├── netdown25.jpeg ├── netdown26.png ├── netdown27.jpeg ├── netdown28.webp ├── netdown29.png ├── netdown3.png ├── netdown4.png ├── netdown5.webp ├── netdown6.jpeg ├── netdown7.webp ├── netdown8.webp ├── netdown9.webp ├── pointer1.webp ├── pointer10.webp ├── pointer11.webp ├── pointer12.webp ├── pointer13.webp ├── pointer14.webp ├── pointer15.webp ├── pointer16.webp ├── pointer17.webp ├── pointer18.webp ├── pointer19.webp ├── pointer2.webp ├── pointer20.webp ├── pointer21.webp ├── pointer22.webp ├── pointer23.webp ├── pointer24.webp ├── pointer25.webp ├── pointer26.webp ├── pointer27.webp ├── pointer28.webp ├── pointer29.webp ├── pointer3.webp ├── pointer30.webp ├── pointer31.webp ├── pointer32.webp ├── pointer4.webp ├── pointer5.webp ├── pointer6.webp ├── pointer7.webp ├── pointer8.webp ├── pointer9.webp ├── protocol1.webp ├── protocol2.webp ├── protocol3.webp ├── protocol4.webp ├── protocol5.webp ├── protocol6.jpeg ├── protocol7.webp ├── protocol8.webp ├── reactor1.jpg ├── reactor2.jpg ├── select1.webp ├── select2.webp ├── select3.webp ├── select4.webp ├── select5.webp ├── select6.webp ├── select7.webp ├── sendrecvreturnvalue1.png ├── sendrecvreturnvalue2.png ├── sendway1.webp ├── sendway2.webp ├── socketmode1.webp ├── socketmode2.webp ├── socketmode3.webp ├── socketmode4.webp ├── sp1.webp ├── sp2.webp ├── stack1.png ├── stack2.png ├── stack3.png ├── stack4.png ├── stack5.png ├── stack6.png ├── tcp1.webp ├── tcp2.webp ├── tcpdump1.webp ├── tcpdump10.webp ├── tcpdump2.webp ├── tcpdump3.webp ├── tcpdump4.webp ├── tcpdump5.webp ├── tcpdump6.webp ├── tcpdump7.webp ├── tcpdump8.png ├── tcpdump9.png ├── telnet1.webp ├── telnet2.webp ├── telnet3.webp ├── telnet4.webp ├── tt1.png ├── tt10.png ├── tt11.jpg ├── tt11.png ├── tt12.jpg ├── tt13.jpg ├── tt14.jpg ├── tt14.png ├── tt15.jpg ├── tt15.png ├── tt16.jpg ├── tt16.png ├── tt17.png ├── tt18.png ├── tt19.png ├── tt2.png ├── tt20.png ├── tt21.png ├── tt22.png ├── tt23.png ├── tt24.png ├── tt25.png ├── tt26.png ├── tt27.png ├── tt28.png ├── tt29.png ├── tt3.png ├── tt30.png ├── tt31.png ├── tt32.png ├── tt33.png ├── tt4.png ├── tt5.png ├── tt6.png ├── tt7.jpeg ├── tt8.png ├── tt9.png ├── vargs.png ├── vs1.png ├── vs2.png ├── vs3.png ├── vs4.png ├── vsdebuglinux1.webp ├── vsdebuglinux10.webp ├── vsdebuglinux2.jpeg ├── vsdebuglinux3.webp ├── vsdebuglinux4.webp ├── vsdebuglinux5.webp ├── vsdebuglinux6.webp ├── vsdebuglinux7.jpeg ├── vsdebuglinux8.webp ├── vsdebuglinux9.webp ├── websocket1.webp ├── zhyz1.webp ├── zhyz10.webp ├── zhyz11.webp ├── zhyz12.webp ├── zhyz13.png ├── zhyz14.png ├── zhyz15.webp ├── zhyz16.webp ├── zhyz17.webp ├── zhyz18.webp ├── zhyz19.webp ├── zhyz2.webp ├── zhyz20.webp ├── zhyz21.webp ├── zhyz22.webp ├── zhyz23.webp ├── zhyz24.webp ├── zhyz25.webp ├── zhyz26.webp ├── zhyz27.webp ├── zhyz28.webp ├── zhyz29.webp ├── zhyz3.webp ├── zhyz30.webp ├── zhyz31.webp ├── zhyz32.webp ├── zhyz33.webp ├── zhyz34.webp ├── zhyz35.webp ├── zhyz36.png ├── zhyz37.jpeg ├── zhyz38.png ├── zhyz39.jpeg ├── zhyz4.webp ├── zhyz40.png ├── zhyz41.jpeg ├── zhyz42.png ├── zhyz43.jpeg ├── zhyz44.png ├── zhyz45.png ├── zhyz46.png ├── zhyz47.jpeg ├── zhyz48.png ├── zhyz49.png ├── zhyz5.webp ├── zhyz6.webp ├── zhyz7.webp ├── zhyz8.webp └── zhyz9.webp ├── leveldb源码分析 ├── README.md ├── leveldb源码分析1.md ├── leveldb源码分析10.md ├── leveldb源码分析11.md ├── leveldb源码分析12.md ├── leveldb源码分析13.md ├── leveldb源码分析14.md ├── leveldb源码分析15.md ├── leveldb源码分析16.md ├── leveldb源码分析17.md ├── leveldb源码分析18.md ├── leveldb源码分析19.md ├── leveldb源码分析2.md ├── leveldb源码分析20.md ├── leveldb源码分析21.md ├── leveldb源码分析22.md ├── leveldb源码分析3.md ├── leveldb源码分析4.md ├── leveldb源码分析5.md ├── leveldb源码分析6.md ├── leveldb源码分析7.md ├── leveldb源码分析8.md └── leveldb源码分析9.md ├── libevent源码深度剖析 ├── index.md ├── libevent源码深度剖析01.md ├── libevent源码深度剖析02.md ├── libevent源码深度剖析03.md ├── libevent源码深度剖析04.md ├── libevent源码深度剖析05.md ├── libevent源码深度剖析06.md ├── libevent源码深度剖析07.md ├── libevent源码深度剖析08.md ├── libevent源码深度剖析09.md ├── libevent源码深度剖析10.md ├── libevent源码深度剖析11.md ├── libevent源码深度剖析12.md └── libevent源码深度剖析13.md ├── wechat_pay.png ├── zfb_pay.png ├── 作者的故事 ├── README.md ├── 我是如何年薪五十万的.md └── 我的2019.md ├── 后端开发相关的书籍 ├── README.md └── 后台开发应该读的书.md ├── 多线程 ├── README.md ├── 后台C++开发你一定要知道的条件变量.md └── 整型变量赋值是原子操作吗?.md ├── 服务器开发案例实战 ├── .DS_Store ├── 1从一款多人联机实时对战游戏开始.md ├── 2最后一战概况.md ├── 3CSBattleMgr服务源码研究.md ├── 4LogServer源码探究.md ├── README.md ├── 从零实现一个http服务器.md ├── 从零实现一个邮件收发客户端.md ├── 从零实现一款12306刷票软件.md └── 从零开发一个WebSocket服务器.md ├── 游戏开发专题 ├── 10十万在线的WebGame的数据库设计思路.md ├── 11一种高性能网络游戏服务器架构设计.md ├── 12经典游戏服务器端架构概述.md ├── 13游戏跨服架构进化之路.md ├── 1游戏服务器开发的基本体系与服务器端开发的一些建议.md ├── 2网络游戏服务器开发框架设计介绍.md ├── 3游戏后端开发需要掌握的知识.md ├── 4关于游戏服务端架构的整理.md ├── 5各类游戏对应的服务端架构.md ├── 6从腾讯QQgame高性能服务器集群架构看“分而治之”与“自治”等分布式架构设计原则.md ├── 7QQ游戏百万人同时在线服务器架构实现.md ├── 8大型多人在线游戏服务器架构设计.md ├── 9百万用户级游戏服务器架构设计.md └── README.md ├── 程序员必知必会的网络命令 ├── Linuxtcpdump使用介绍.md ├── Linux网络故障排查的瑞士军刀.md ├── README.md ├── 从抓包的角度分析connect函数的连接过程.md ├── 做Java或者C++开发都应该知道的lsof命令.md ├── 利用telnet命令发电子邮件.md └── 服务器开发中网络数据分析与故障排查经验漫谈.md ├── 程序员的烦心事 ├── README.md ├── 我是一名程序员,结婚时女友要求我用两年的工资作为彩礼,我该不该答应?.md └── 拒绝了一家公司的offer后,他们的副总和hr总监同时打电话来询问拒绝原因并极力要求加入,我该不该去?.md ├── 程序员的简历 ├── README.md └── 程序员如何写简历.md ├── 程序员的薪资与年终奖那些事儿 ├── .DS_Store ├── README.md ├── 技术面试与HR谈薪资技巧.md ├── 聊一聊程序员如何增加收入.md └── 谈一谈年终奖.md ├── 程序员面试题精讲 ├── LinuxCC++后端开发面试问哪些问题.md ├── README.md ├── 我面试后端开发经理的经历.md ├── 网络通信题目集锦.md ├── 聊聊如何拿大厂的offer.md └── 腾讯后台开发实习生技能要求.md ├── 网络编程 ├── .DS_Store ├── Linuxepoll模型(含LT模式和ET模式详解).md ├── README.md ├── TCP协议如何解决粘包、半包问题.md ├── bind函数重难点解析.md ├── connect函数在阻塞和非阻塞模式下的行为.md ├── select函数重难点解析.md ├── socket的阻塞模式和非阻塞模式.md ├── 服务器开发通信协议设计介绍.md ├── 服务器端发数据时,如果对端一直不收,怎么办?.md ├── 网络通信中收发数据的正确姿势.md └── 非阻塞模式下send和recv函数的返回值.md ├── 职业规划 ├── README.md ├── 写给那些傻傻想做服务器开发的朋友.md ├── 给工作4年迷茫的程序员们的一点建议.md └── 聊聊技术人员的常见的职业问题.md ├── 自我提升与开源代码 ├── 2020年好好读一读开源代码吧.md └── README.md └── 高性能服务器框架设计 ├── .DS_Store ├── C++高性能服务器网络框架设计细节.md ├── README.md ├── Reactor模式.md ├── 业务数据处理一定要单独开线程吗.md ├── 主线程与工作线程的分工.md ├── 如何设计断线自动重连机制.md ├── 实例:一个服务器程序的架构介绍.md ├── 心跳包机制设计详解.md ├── 日志系统的设计.md ├── 错误码系统的设计.md └── 高性能服务器架构设计总结.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | articles/.DS_Store 3 | -------------------------------------------------------------------------------- /articles/C++必知必会的知识点/README.md: -------------------------------------------------------------------------------- 1 | ## C++必知必会的知识点 2 | 3 | 4 | * [如何成为一名合格的C/C++开发者?](如何成为一名合格的CC++开发者?.md) 5 | 6 | * [不定参数函数实现var_arg系列的宏](不定参数函数实现var_arg系列的宏.md) 7 | 8 | * [你一定要搞明白的C函数调用方式与栈原理](你一定要搞明白的C函数调用方式与栈原理.md) 9 | 10 | * [深入理解C/C++中的指针](深入理解CC++中的指针.md) 11 | 12 | * [详解C++11中的智能指针](详解C++11中的智能指针.md) 13 | 14 | * [C++17结构化绑定](C++17结构化绑定.md) 15 | 16 | * [C++必须掌握的pimpl惯用法](C++必须掌握的pimpl惯用法.md) 17 | 18 | * [用Visual Studio调试Linux程序](用VisualStudio调试Linux程序.md) 19 | 20 | * [如何使用Visual Studio管理和阅读开源项目代码](如何使用VisualStudio管理和阅读开源项目代码.md) 21 | 22 | * [利用cmake工具生成Visual Studio工程文件](利用cmake工具生成VisualStudio工程文件.md) 23 | 24 | -------------------------------------------------------------------------------- /articles/C++必知必会的知识点/利用cmake工具生成VisualStudio工程文件.md: -------------------------------------------------------------------------------- 1 | ## 利用 cmake 工具生成 Visual Studio 工程文件 2 | 3 | 对于习惯了 Visual Studio 强大的管理项目、编码和调试功能的读者来说,在 Linux 下使用 gcc/g++ 编译、使用 gdb 调试是一件何其痛苦的事情,对于大多数的开源 C/C++ 项目,如果我们不在意 Windows 和 Linux 在一些底层 API 接口上的使用差别,想熟悉该项目的执行脉络和原理,在 Windows 上使用 Visual Studio 调试该项目也未尝不可。凡是可以使用 CMake 工具编译的 Linux 程序(即提供了 **CMakeLists.txt** 文件),我们同样也可以利用 CMake 工具生成 Windows 上的 Visual Studio 工程文件。 4 | 5 | 这里我们以著名的开源网络库 **libuv** 为例。 6 | 7 | 从 **libuv** 的官方地址提供的下载链接:https://dist.libuv.org/dist/ 下载最新的 **libuv** 的源码得到文件 **libuv-v1.31.0.tar.gz**(笔者写作此书时,libuv 最新版本是 1.31.0),解压该文件。作者的机器上我将代码解压至 **F:\mycode\libuv-v1.31.0\** ,解压后的目录中确实存在一个 **CMakeLists.txt** 文件,如下图所示: 8 | 9 | ![img](../imgs/cmake1.png) 10 | 11 | 启动 Windows 上的 CMake 图形化工具(**cmake-gui**),按下图进行设置: 12 | 13 | ![img](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==) 14 | 15 | 设置完成之后,点击界面上的**Configure** 按钮,会提示 vsprojects 目录不存在,提示是否创建,我们点击 **Yes** 进行创建。 16 | 17 | ![img](../imgs/cmake2.png) 18 | 19 | 如果您的机器上安装了多个版本的Visual Studio,接下来会弹窗对话框让我们选择要生成的工程文件对应的 Visual Studio 版本号。读者可以根据自己的实际情况按需选择。我这里选择 Visual Studio 2019。 20 | 21 | ![img](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==) 22 | 23 | ![img](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==) 24 | 25 | 点击 **Finish** 按钮后开始启动 CMake 的检测和配置工作。等待一会儿,CMake 底部的输出框中提示 “Configuring Done” 表示配置工作已经完成。 26 | 27 | 28 | 29 | ![img](../imgs/cmake3.png) 30 | 31 | 32 | 33 | 接下来点击 **Generate** 按钮即可生成所选版本的 Visual Studio 工程文件,生成的文件位于 vsprojects 目录。 34 | 35 | ![img](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==) 36 | 37 | 我们可以在界面上点击按钮 **Open Project** 按钮直接打开工程文件,也可以找到对应目录下的 **libuv.sln** 打开。 38 | 39 | 打开后如下图所示: 40 | 41 | ![img](../imgs/cmake4.png) 42 | 43 | 接下来,我们就可以使用 Visual Studio 愉快地进行编译和调试了。 44 | 45 | 46 | 47 | 让我们再深入聊一下上述过程:在点击 **Configure** 按钮之后,和在 Linux 下执行 cmake 命令一样,CMake 工具也是在检测所在的系统环境是否匹配 CMakeLists.txt 中定义的各种环境,本质上是生成了一份可以在 Windows 上编译和运行的代码(也就是说该源码支持在 Windows 上运行) 。因此,对于很多虽然提供了 CMakeLists.txt 文件但并不支持在 Windows 上运行的的 Linux 工程,虽然利用上述方法也能最终生成 Visual Studio 工程文件,但是这些文件并不能在 Windows 上直接无错编译和调试。 48 | 49 | > 由于不同的 CMake 版本支持的 CMakeLists.txt 中的语法可能略有细微差别,有些 CMakeLists.txt 文件在使用上述方法 **configure** 时可能会产生一些错误,需要读者做些修改才能通过。 50 | -------------------------------------------------------------------------------- /articles/C++必知必会的知识点/如何使用VisualStudio管理和阅读开源项目代码.md: -------------------------------------------------------------------------------- 1 | ## 如何使用 Visual Studio 管理和阅读开源项目代码 2 | 3 | 对于 Linux C/C++ 项目,虽然我们在 Linux 系统中使用 gdb 去调试,但是通常情况下对于 C/C++ 项目笔者一般习惯使用 **Visual Studio** 去做项目管理,Visual Studio 提供了强大的 C/C++ 项目开发和管理能力。这里以 redis 源码为例,介绍一下如何将这种开源项目整体添加到 Visual Studio 的解决方案中去。 4 | 5 | 1. 启动 Visual Studio 新建一个空的 Win32 控制台程序。(工程建好后,关闭该工程防止接下来的步骤中文件占用导致的无法移动。) 6 | 7 | ![img](../imgs/vs1.png) 8 | 9 | \2. 这样会在 redis 源码目录下会根据你设置的名称生成一个文件夹(这里是 redis-4.0.1),将该文件夹中所有文件拷贝到 redis 源码根目录,然后删掉生成的这个文件夹。 10 | 11 | ![img](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==) 12 | 13 | 14 | 15 | ![img](../imgs/vs2.png) 16 | 17 | \3. 再次用 Visual Studio 打开 redis-4.0.1.sln 文件,然后在**解决方案资源管理器**视图中点击**显示所有文件**按钮并保持该按钮选中。(如果找不到**解决方案资源管理器**视图,可以在【**视图**】菜单中打开,快捷键 Ctrl + Alt + L。) 18 | 19 | ![img](../imgs/vs3.png) 20 | 21 | 22 | 23 | \4. 然后选中所有需要添加到解决方案中的文件,右键选择菜单【**包括在项目中**】即可,如果文件比较多,Visual Studio 可能需要一会儿才能完成,为了减少等待时间,读者也可以一批一批的添加。 24 | 25 | ![img](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==) 26 | 27 | 28 | 29 | 5.接着选择【**文件**】菜单【**全部保存**】菜单项保存即可(快捷键 **Ctrl + Shift + S** )。 30 | 31 | 最终效果如下图所示: 32 | 33 | ![img](../imgs/vs4.png) 34 | 35 | 36 | 37 | 这样我们就能利用 Visual Studio 强大的功能管理和阅读我们的源码了。 38 | 39 | > 这里要提醒一下读者:**C/C++ 开源项目中一般会使用各种宏去条件编译一些代码,实际生成的二进制文件中不一定包含这些代码,所以在 Visual Studio 中看到某段代码的行号与实际在 gdb 中调试的代码行号不一定相同,在给某一行代码设置断点时请以 gdb 中 list 命令看到的代码行号为准**。 40 | 41 | -------------------------------------------------------------------------------- /articles/C++必知必会的知识点/用VisualStudio调试Linux程序.md: -------------------------------------------------------------------------------- 1 | # 用Visual Studio调试Linux程序 2 | 3 | 用Visual Studio调试Linux程序?你真的没看错,这个是真的,不是标题党。当然如果你说VS2015及以上版本自带的Linux调试插件,那就算了。这些自带的插件调试一个有简单的main函数程序还凑合,稍微复杂点的程序,根本无法编译调试。 4 | 5 | 而本文介绍的主角是VS的另外一款插件Visual GDB,让我们欢迎主角登场,下面是正文。 6 | 7 | 8 | 9 | ## 使用Visual Studio+VisualGDB调试远程Linux程序 10 | 11 | 需要工具: 12 | 13 | 1. Visual Studio 2013或以上版本(以下简称VS) 14 | 2. VisualGDB(一款VS插件,官网为:http://visualgdb.com/) 15 | 3. 含有调试符号的Linux程序文件(该程序文件为调试目标) 16 | 4. Visual Assistant(番茄助手,另外一款VS插件) 17 | 18 | 19 | 20 | 在VS上安装完VisualGDB插件以后,有如下几种方式来对远程Linux机器上的程序进行调试: 21 | 22 | - **方法一、**如果该程序已经启动,则可以使用VS菜单【Debug】->【Attach to Process...】。 23 | 24 | ![](../imgs/vsdebuglinux1.webp) 25 | 26 | 27 | 28 | ![img](../imgs/vsdebuglinux2.jpeg) 29 | 30 | ![](../imgs/vsdebuglinux3.webp) 31 | 32 | ![](../imgs/vsdebuglinux4.webp) 33 | 34 | ![](../imgs/vsdebuglinux5.webp) 35 | 36 | 37 | 38 | 这种方法有个缺点是,不能从开始启动的main函数处添加断点,自始至终地调试程序,查看完整程序运行脉络,所以下面推荐方法二。 39 | 40 | - 方法二、利用VS启动远程Linux机器上一个Linux程序文件进行调试。选择VS菜单【Debug】 ->【Quick Debugwith GDB】。 41 | 42 | ![](../imgs/vsdebuglinux6.webp) 43 | 44 | 需要注意的地方,已经在上图中标红框。这里简单地解释一下: 45 | 46 | 如果你安装了交叉编译环境Target可以选择MinGW/Cygwin,否则就选择远程Linux系统。这里如果不存在一个ssh连接,则需要创建一个。 47 | 48 | 49 | 50 | Debugged program是需要设置的被调试程序的路径,位于远程Linux机器上。 51 | 52 | Arguments是该调试程序需要设置的命令行参数,如果被调试程序不需要命令行参数可以不设置。 53 | 54 | Working directory是被调试程序运行的工作目录。 55 | 56 | 57 | 58 | 另外建议勾选上Initial breakpoint in main,这样启动调试时,程序就会停在程序入口处。 59 | 60 | 61 | 62 | 这样,我们就可以利用VS强大的功能去查看程序的各种状态了,常用的面板,如【内存】【线程】【观察】【堆栈】【GDB Session】【断点】等窗口位于VS 菜单【Debug】->【Windows】菜单下,注意,有些窗口只有在调试状态下才可见。这里有两个值得强调一下的功能是: 63 | 64 | 1. **GDB Session****窗口**,在这个窗口里面可以像原来直接使用gdb调试一样输入gdb指令来进行调试。 65 | 66 | ![img](../imgs/vsdebuglinux7.jpeg) 67 | 68 | 69 | 70 | 1. **SSH console****窗口**,这个窗口类似一个远程操作Linux系统的应用程序如xshell、SecureCRT。 71 | 72 | ![](../imgs/vsdebuglinux8.webp) 73 | 74 | 75 | 76 | 现在还剩下一个问题,就是我们虽然在调试时可视化地远程查看一个Linux进程的状态信息,但很多类型的定义和什么却无法看到。解决这个问题的方法就是你可以先在VS里面建立一个工程,导入你要调试的程序的源代码目录。然后利用方法一或者方法二去启动调试程序。这个时候你想查看某个类型的定义或什么只要利用Visual Assit的查看源码功能即可,快捷键是Alt + G。 77 | 78 | ![](../imgs/vsdebuglinux9.webp) 79 | 80 | 81 | 82 | 需要注意的时:同时安装了Visual Assist和VisualGDB后,后者也会提供一个go按钮去查找源码定义,但这个功能远不如Visual Assist按钮好用,我们可以禁用掉它来使用Visual Assist的Go功能。禁用方法,打开菜单:【Tools】->【Option...】: 83 | 84 | ![](../imgs/vsdebuglinux10.webp) 85 | 86 | 87 | 88 | 然后重启VS即可。 89 | 90 | 91 | 92 | 到这里,既可以查看源码,也可以调试程序了。 93 | 94 | 95 | 96 | VisualGDB 下载地址: 97 | 98 | 链接:https://share.weiyun.com/57aGHLM 密码:kj9ahs -------------------------------------------------------------------------------- /articles/Memcached源码分析/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/Memcached源码分析/.DS_Store -------------------------------------------------------------------------------- /articles/Memcached源码分析/07cas属性.md: -------------------------------------------------------------------------------- 1 | # Memcached源码阅读七 cas属性 2 | 3 | cas即`compare and set`或者`compare and swap`,是实现**乐观锁**的一种技术,乐观锁是相对悲观锁来说的,所谓**悲观锁**是在数据处理过程中,完全锁定,这种能完全保证数据的一致性,但在多线程情况下,**并发性能差**,通常是使用各种锁技术实现;而乐观锁是通过版本号机制来实现数据一致性,过程中会使用CPU提供的原子操作指令,乐观锁能提高系统的并发性能,Memcached使用cas是保证数据的一致性,不是严格为了实现锁。 4 | 5 | `Memcached`是多客户端应用,在多个客户端修改同一个数据时,会出现相互覆盖的情况,在这种情况下,使用cas版本号验证,可以有效的保证数据的一致性,Memcached默认是打开cas属性的,每次存储数据时,都会生成其cas值并和item一起存储,后续的get操作会返回系统生成的cas值,在执行set等操作时,需要将cas值传入,下面我们看看Memcached内部是如何实现cas的,关于如何使用Mecached的CAS协议,请参考文章:Memcached的CAS协议(链接:http://langyu.iteye.com/blog/680052)。 6 | 7 | ``` 8 | //为新的item生成cas值 9 | uint64_t get_cas_id(void) 10 | { 11 | static uint64_t cas_id = 0; 12 | return ++cas_id; 13 | } 14 | 15 | //这段代码是store_item的代码片段,这里是执行cas存储时执行的判断逻辑, 16 | else if (ITEM_get_cas(it) == ITEM_get_cas(old_it))//cas值一致 17 | { 18 | pthread_mutex_lock(&c->thread->stats.mutex); 19 | c->thread->stats.slab_stats[old_it->slabs_clsid].cas_hits++; 20 | pthread_mutex_unlock(&c->thread->stats.mutex); 21 | 22 | item_replace(old_it, it, hv);//执行存储逻辑 23 | stored = STORED; 24 | } 25 | //cas值不一致,不进行实际的存储 26 | else 27 | { 28 | pthread_mutex_lock(&c->thread->stats.mutex); 29 | c->thread->stats.slab_stats[old_it->slabs_clsid].cas_badval++; 30 | //更新统计信息 31 | pthread_mutex_unlock(&c->thread->stats.mutex); 32 | 33 | if (settings.verbose > 1) 34 | { 35 | //打印错误日志 36 | fprintf(stderr, "CAS: failure: expected %llu, got %llu\n", 37 | (unsigned long long) ITEM_get_cas(old_it), 38 | (unsigned long long) ITEM_get_cas(it)); 39 | } 40 | stored = EXISTS; 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /articles/Memcached源码分析/08内存池.md: -------------------------------------------------------------------------------- 1 | # Memcached源码阅读八 内存池 2 | 3 | `Memcached`内部维护了一个**内存池**来减少频繁的`malloc`和`free`,在该内存池的基础上面实现了**slab内存管理**,下面简单介绍下内存池的实现,大家在实现类似结构时,可以做个参考。 4 | 5 | ``` 6 | static void *mem_base = NULL;//mem_base指向新申请的内存空间,指向整个内存空间的头部 7 | static void *mem_current = NULL;//指向已经分配过的空间,且指向已经分配了空间的尾部 8 | static size_t mem_avail = 0;//剩余空间大小 9 | 10 | //部分初始化操作 11 | mem_limit = limit;//初始容量 12 | mem_base = malloc(mem_limit);//申请内存空间 13 | 14 | if (mem_base != NULL) //如果不为空 15 | { 16 | mem_current = mem_base; 17 | //当前还没分配,所以其指向为整个空间 18 | mem_avail = mem_limit; 19 | //可用空间为满 20 | } else { 21 | fprintf(stderr, "Warning: Failed to allocate requested memory in" 22 | " one large chunk.\nWill allocate in smaller chunks\n"); 23 | } 24 | 25 | //分配空间的过程,分配size大小的空间 26 | static void *memory_allocate(size_t size) { 27 | void *ret; 28 | 29 | //如果未初始化 30 | if (mem_base == NULL) { 31 | ret = malloc(size); 32 | } else { 33 | ret = mem_current; 34 | 35 | if (size > mem_avail) { 36 | return NULL; 37 | } 38 | 39 | //执行对齐操作 40 | if (size % CHUNK_ALIGN_BYTES) { 41 | size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES); 42 | } 43 | 44 | mem_current = ((char*)mem_current) + size; 45 | if (size < mem_avail) { 46 | mem_avail -= size; 47 | } else { 48 | mem_avail = 0; 49 | } 50 | } 51 | 52 | return ret; 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /articles/Memcached源码分析/09连接队列.md: -------------------------------------------------------------------------------- 1 | # Memcached源码阅读九 连接队列 2 | 3 | `Memcached`中**Master线程**和**Worker线程**之间通信连接信息时,是通过连接队列来通信的,即Master线程投递一个消息到Worker线程的连接队列中,Worker线程从连接队列中读取链接信息来执行连接操作,下面我们简单分析下Memcached的连接队列结构。 4 | 5 | ``` 6 | typedef struct conn_queue_item CQ_ITEM;//每个连接信息的封装 7 | struct conn_queue_item { 8 | int sfd;//accept之后的描述符 9 | enum conn_states init_state;//连接的初始状态 10 | int event_flags;//libevent标志 11 | int read_buffer_size;//读取数据缓冲区大小 12 | enum network_transport transport;//内部通信所用的协议 13 | CQ_ITEM *next;//用于实现链表的指针 14 | }; 15 | 16 | typedef struct conn_queue CQ;//连接队列的封装 17 | struct conn_queue { 18 | CQ_ITEM *head;//头指针,注意这里是单链表,不是双向链表 19 | CQ_ITEM *tail;//尾部指针, 20 | pthread_mutex_t lock;//锁 21 | pthread_cond_t cond;//条件变量 22 | }; 23 | 24 | //连接队列初始化 25 | static void cq_init(CQ *cq) { 26 | pthread_mutex_init(&cq->lock, NULL);//初始化锁 27 | pthread_cond_init(&cq->cond, NULL);//初始化条件变量 28 | cq->head = NULL; 29 | cq->tail = NULL; 30 | } 31 | 32 | //获取一个连接 33 | static CQ_ITEM *cq_pop(CQ *cq) { 34 | CQ_ITEM *item; 35 | 36 | pthread_mutex_lock(&cq->lock);//执行加锁操作 37 | item = cq->head; 38 | //获得头部指针指向的数据 39 | if (NULL != item) { 40 | //更新头指针信息 41 | cq->head = item->next; 42 | //这里为空的话,则尾指针也为空,链表此时为空 43 | if (NULL == cq->head) 44 | cq->tail = NULL; 45 | } 46 | //释放锁操作 47 | pthread_mutex_unlock(&cq->lock); 48 | 49 | return item; 50 | } 51 | 52 | //添加一个连接信息 53 | static void cq_push(CQ *cq, CQ_ITEM *item) { 54 | item->next = NULL; 55 | 56 | pthread_mutex_lock(&cq->lock);//执行加锁操作 57 | //如果链表目前是空的 58 | if (NULL == cq->tail) 59 | //则头指针指向该结点 60 | cq->head = item; 61 | else 62 | cq->tail->next = item;//添加到尾部 63 | 64 | cq->tail = item; 65 | //尾部指针后移 66 | pthread_cond_signal(&cq->cond); 67 | //唤醒条件变量,如果有阻塞在该条件变量的线程,则会唤醒该线程 68 | pthread_mutex_unlock(&cq->lock); 69 | } 70 | 71 | //创建连接队列 72 | static CQ_ITEM *cqi_new(void) { 73 | CQ_ITEM *item = NULL; 74 | pthread_mutex_lock(&cqi_freelist_lock); 75 | //加锁,保持数据同步 76 | if (cqi_freelist) { 77 | //更新空闲链表信息 78 | item = cqi_freelist; 79 | cqi_freelist = item->next; 80 | } 81 | pthread_mutex_unlock(&cqi_freelist_lock); 82 | 83 | //如果空闲链表没有多余的链接 84 | if (NULL == item) { 85 | int i; 86 | 87 | //初始化64个空闲连接信息 88 | item = malloc(sizeof(CQ_ITEM) * ITEMS_PER_ALLOC); 89 | if (NULL == item) 90 | return NULL; 91 | 92 | //将空闲的连接信息进行链接 93 | for (i = 2; i < ITEMS_PER_ALLOC; i++) 94 | item[i - 1].next = &item[i]; 95 | 96 | pthread_mutex_lock(&cqi_freelist_lock); 97 | item[ITEMS_PER_ALLOC - 1].next = cqi_freelist;//加入到空闲链表中 98 | cqi_freelist = &item[1]; 99 | pthread_mutex_unlock(&cqi_freelist_lock); 100 | } 101 | 102 | return item; 103 | } 104 | 105 | //释放item,也就是将item添加到空闲链表中 106 | static void cqi_free(CQ_ITEM *item) { 107 | pthread_mutex_lock(&cqi_freelist_lock); 108 | item->next = cqi_freelist; 109 | cqi_freelist = item; 110 | pthread_mutex_unlock(&cqi_freelist_lock); 111 | } 112 | ``` 113 | 114 | 空闲链表类似于一种**连接池**的实现,服务器开发中经常需要各种池操作,大家在实现类似池时,可以做参考。 115 | -------------------------------------------------------------------------------- /articles/Memcached源码分析/10Hash表操作.md: -------------------------------------------------------------------------------- 1 | # Memcached源码阅读十 Hash表操作 2 | 3 | `Memcached`的**Hash表**用来提高**数据访问性能**,通过链接法来解决Hash冲突,当Hash表中数据多余Hash表容量的1.5倍时,Hash表就会扩容,Memcached的Hash表操作没什么特别的,我们这里简单介绍下Memcached里面的Hash表操作。 4 | 5 | ``` 6 | //hash表插入元素 7 | int assoc_insert(item *it, const uint32_t hv) { 8 | unsigned int oldbucket; 9 | 10 | //如果已经开始扩容,且扩容的桶编号大于目前的item所在桶的编号 11 | if (expanding && 12 | (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket) 13 | { 14 | //这里是类似单链表的,按单链表的操作进行插入 15 | it->h_next = old_hashtable[oldbucket]; 16 | old_hashtable[oldbucket] = it; 17 | } else { 18 | //已经扩容,则按新的Hash规则进行路由 19 | it->h_next = primary_hashtable[hv & hashmask(hashpower)]; 20 | //这里在新的Hash表中执行单链表插入 21 | primary_hashtable[hv & hashmask(hashpower)] = it; 22 | } 23 | 24 | hash_items++;//元素个数+1 25 | if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2) { 26 | //开始扩容 27 | assoc_start_expand();//唤醒扩容条件变量 28 | } 29 | 30 | MEMCACHED_ASSOC_INSERT(ITEM_key(it), it->nkey, hash_items); 31 | return 1; 32 | } 33 | 34 | //hash表删除元素 35 | void assoc_delete(const char *key, const size_t nkey, const uint32_t hv) { 36 | item **before = _hashitem_before(key, nkey, hv); 37 | //获得item对应的桶的前一个元素 38 | if (*before) { 39 | item *nxt; 40 | hash_items--;//元素个数-1 41 | MEMCACHED_ASSOC_DELETE(key, nkey, hash_items); 42 | nxt = (*before)->h_next;//执行单链表的删除操作 43 | (*before)->h_next = 0; 44 | *before = nxt; 45 | return; 46 | } 47 | assert(*before != 0); 48 | } 49 | ``` 50 | 51 | 像Hash表的扩容,初始化等已经在其他博客中介绍过了,这里就不在阐述。 52 | -------------------------------------------------------------------------------- /articles/Memcached源码分析/11LRU操作.md: -------------------------------------------------------------------------------- 1 | # Memcached源码阅读十一 LRU操作 2 | 3 | `LRU`是最近最少使用的简称,该技术经常用来实现**cache数据更新**,Memcached使用LRU技术来淘汰老的数据,Memcached默认是启用LRU操作的,在这种情况下所有的set操作都会成功,如果Memcached的内存池已经使用完,则会淘汰老数据来存放新数据,如果关闭了Memcached的LRU,则当Memcached没有多余的内存空间时,Memcached之间返回错误,下面我们分析下LRU的相关操作。 4 | 5 | ![](../imgs/memcached1.webp) 6 | 7 | 里面再附一张`Memcached`的**内存结构图**,从图中可以看到LRU队列保持这已经分配出去的item的结构(图中指针为单链表,这里画的有误,其实是双向链表),同时每个`slabclass`由两个指针来维护该表,即`heads`和`tails`指针,分别指向最老的数据和最新的数据,这样便于LRU链表的操作。 8 | 9 | ``` 10 | //每个slabclass各有一个指针 11 | static item *heads[LARGEST_ID]; 12 | static item *tails[LARGEST_ID]; 13 | 14 | //将item加入到对应classid的LRU链的head,这里是item加入到LRU链表中 15 | static void item_link_q(item *it) { 16 | /* item is the new head */ 17 | item **head, **tail; 18 | assert(it->slabs_clsid < LARGEST_ID); 19 | assert((it->it_flags & ITEM_SLABBED) == 0); 20 | 21 | head = &heads[it->slabs_clsid]; 22 | tail = &tails[it->slabs_clsid]; 23 | assert(it != *head); 24 | assert((*head && *tail) || (*head == 0 && *tail == 0)); 25 | it->prev = 0; 26 | it->next = *head; 27 | if (it->next) it->next->prev = it;//执行插入数据操作 28 | *head = it; 29 | if (*tail == 0) *tail = it; 30 | sizes[it->slabs_clsid]++; 31 | return; 32 | } 33 | 34 | //将item从对应classid的LRU链上移除,这里是item从LRU链表中删除 35 | static void item_unlink_q(item *it) { 36 | item **head, **tail; 37 | assert(it->slabs_clsid < LARGEST_ID); 38 | head = &heads[it->slabs_clsid]; 39 | tail = &tails[it->slabs_clsid]; 40 | 41 | if (*head == it) { 42 | assert(it->prev == 0); 43 | *head = it->next; 44 | } 45 | if (*tail == it) { 46 | assert(it->next == 0); 47 | *tail = it->prev; 48 | } 49 | assert(it->next != it); 50 | assert(it->prev != it); 51 | 52 | if (it->next) it->next->prev = it->prev;//断开连接 53 | if (it->prev) it->prev->next = it->next; 54 | sizes[it->slabs_clsid]--; 55 | return; 56 | } 57 | ``` 58 | 59 | 注:图片链接自 http://kenby.iteye.com/blog/1423989 60 | -------------------------------------------------------------------------------- /articles/Memcached源码分析/14item结构.md: -------------------------------------------------------------------------------- 1 | # Memcached源码阅读十四 item结构 2 | 3 | `item`是`Memcached`中抽象实际数据的结构,我们分析下item的一些特性,便于后续Memcached的其他特性分析。 4 | 5 | ``` 6 | typedef struct _stritem { 7 | struct _stritem *next;//item在slab中存储时,是以双链表的形式存储的,next即后向指针 8 | struct _stritem *prev;//prev为前向指针 9 | struct _stritem *h_next;//Hash桶中元素的链接指针 10 | rel_time_t time;//最近访问时间 11 | rel_time_t exptime;//过期时间 12 | int nbytes;//数据大小 13 | unsigned short refcount;//引用次数 14 | uint8_t nsuffix;//不清楚什么意思? 15 | uint8_t it_flags;//不清楚什么意思? 16 | uint8_t slabs_clsid;//标记item属于哪个slabclass下 17 | uint8_t nkey;//key的长度 18 | union { 19 | uint64_t cas; 20 | char end; 21 | } data[];//真实的数据信息 22 | } item; 23 | ``` 24 | 25 | 其结构图如下所示: 26 | 27 | ![](../imgs/memcached2.webp) 28 | 29 | Item由两部分组成,item的**属性信息**和item的**数据部分**,属性信息解释如上,数据部分包括`cas`,`key`和真实的`value`信息,item在内存中的存储形式如下: 30 | 31 | ![](../imgs/memcached3.webp) 32 | 33 | 这个图画出了部分结构,还有Hash表的结构没有画出。 34 | 35 | 这里大概介绍了item的一些信息,后面我们会分析item插入Hash表等信息。 36 | -------------------------------------------------------------------------------- /articles/Memcached源码分析/README.md: -------------------------------------------------------------------------------- 1 | ## Memcached源码分析 2 | 3 | * [00 服务器资源调整](00服务器资源调整.md) 4 | 5 | * [01 初始化参数解析](01初始化参数解析.md) 6 | 7 | * [02 网络监听的建立](02网络监听的建立.md) 8 | 9 | * [03 网络连接建立](03网络连接建立.md) 10 | 11 | * [04 内存初始化](04内存初始化.md) 12 | 13 | * [05 资源初始化](05资源初始化.md) 14 | 15 | * [06 get过程](06get过程.md) 16 | 17 | * [07 cas属性](07cas属性.md) 18 | 19 | * [08 内存池](08内存池.md) 20 | 21 | * [09 连接队列](09连接队列.md) 22 | 23 | * [10 Hash表操作](10Hash表操作.md) 24 | 25 | * [12 set操作](12set操作.md) 26 | 27 | * [13 do_item_alloc操作](13do_item_alloc操作.md) 28 | 29 | * [14 item结构](14item结构.md) 30 | 31 | * [15 Hash表扩容](15Hash表扩容.md) 32 | 33 | * [16 线程交互](16线程交互.md) 34 | 35 | * [17 状态机](17状态机.md) 36 | 37 | ​ -------------------------------------------------------------------------------- /articles/TeamTalk源码解析/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/TeamTalk源码解析/.DS_Store -------------------------------------------------------------------------------- /articles/TeamTalk源码解析/01TeamTalk介绍.md: -------------------------------------------------------------------------------- 1 | # 01 TeamTalk介绍 2 | 3 | TeamTalk是蘑菇街开源的一款企业内部用的即时通讯软件(Enterprise IM),类似腾讯的RTX。网上也有很多的介绍,我这里也有写几遍关于这款产品的“流水账”,一方面对自己这段时间的阅读其代码做个总结,尽量做个既能宏观上从全局来介绍,又不缺少很多有价值的微观细节,另一方面如果对于作为读者的您有些许帮助,那就善莫大焉了。 4 | 5 | 项目地址github:https://github.com/baloonwj/TeamTalk 6 | 7 | 如果您打不开github,请移步至百度网盘下载:http://pan.baidu.com/s/1slbJVf3 8 | 9 | 关于即时通讯软件本身,我相信使用过QQ的都知道是啥。 10 | 11 | 下载项目解压后目录结构是这样的: 12 | 13 | ![](../imgs/tt1.png) 14 | 15 | 这款即时通讯软件分为服务器端(linux)、pc端、web端、mac端和两个移动端(ios和安卓),源码中使用了大量的开源技术(用项目作者的话说,就是“拿来主义”)。例如通信协议使用了google protobuf,服务器端使用了内存数据库redis,pc端界面库使用的duilib,pc端的日志系统使用的是YAOLOG库、cximage、jsoncpp库等等。在接下来各个端的源码分析中,我们将会深入和细致地介绍。 16 | 17 | 下一篇我将介绍首先介绍服务器端的程序的编译与部署。 -------------------------------------------------------------------------------- /articles/TeamTalk源码解析/09服务器端route_server源码分析.md: -------------------------------------------------------------------------------- 1 | # 09 服务器端route_server源码分析 2 | 3 | route_server的作用主要是用户不同msg_server之间消息路由,其框架部分和前面的服务类似,没有什么好说的。我们这里重点介绍下它的业务代码,也就是其路由细节: 4 | 5 | ```cpp 6 | void CRouteConn::HandlePdu(CImPdu* pPdu) 7 | { 8 | switch (pPdu->GetCommandId()) { 9 | case CID_OTHER_HEARTBEAT: 10 | // do not take any action, heart beat only update m_last_recv_tick 11 | break; 12 | case CID_OTHER_ONLINE_USER_INFO: 13 | _HandleOnlineUserInfo( pPdu ); 14 | break; 15 | case CID_OTHER_USER_STATUS_UPDATE: 16 | _HandleUserStatusUpdate( pPdu ); 17 | break; 18 | case CID_OTHER_ROLE_SET: 19 | _HandleRoleSet( pPdu ); 20 | break; 21 | case CID_BUDDY_LIST_USERS_STATUS_REQUEST: 22 | _HandleUsersStatusRequest( pPdu ); 23 | break; 24 | case CID_MSG_DATA: 25 | case CID_SWITCH_P2P_CMD: 26 | case CID_MSG_READ_NOTIFY: 27 | case CID_OTHER_SERVER_KICK_USER: 28 | case CID_GROUP_CHANGE_MEMBER_NOTIFY: 29 | case CID_FILE_NOTIFY: 30 | case CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY: 31 | _BroadcastMsg(pPdu, this); 32 | break; 33 | case CID_BUDDY_LIST_SIGN_INFO_CHANGED_NOTIFY: 34 | _BroadcastMsg(pPdu); 35 | break; 36 | 37 | default: 38 | log("CRouteConn::HandlePdu, wrong cmd id: %d ", pPdu->GetCommandId()); 39 | break; 40 | } 41 | } 42 | ``` 43 | 44 | 上面是route_server处理的消息类型,我们逐一来介绍: 45 | 46 | 1. CID_OTHER_ONLINE_USER_INFO 47 | 48 | 这个消息是msg_server连接上route_server后告知route_server自己上面的用户登录情况。route_server处理后,只是简单地记录一下每个msg_server上的用户数量和用户id: 49 | 50 | ```cpp 51 | void CRouteConn::_HandleOnlineUserInfo(CImPdu* pPdu) 52 | { 53 | IM::Server::IMOnlineUserInfo msg; 54 | CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength())); 55 | 56 | uint32_t user_count = msg.user_stat_list_size(); 57 | 58 | log("HandleOnlineUserInfo, user_cnt=%u ", user_count); 59 | 60 | for (uint32_t i = 0; i < user_count; i++) { 61 | IM::BaseDefine::ServerUserStat server_user_stat = msg.user_stat_list(i); 62 | _UpdateUserStatus(server_user_stat.user_id(), server_user_stat.status(), server_user_stat.client_type()); 63 | } 64 | } 65 | ``` 66 | 67 | 68 | 69 | 2. CID_OTHER_USER_STATUS_UPDATE 70 | 71 | 这个消息是当某个msg_server上有用户上下线时,msg_server会给route_server发送自己最近的用户数量和在线用户id信息,route_server的处理也就是更新下记录的该msg_server上的用户数量和用户id。 72 | 73 | 3. CID_OTHER_ROLE_SET 74 | 75 | 这个消息没看懂,感觉是确定主从关系的,不过感觉没什么用? 76 | 77 | 4. CID_OTHER_GET_DEVICE_TOKEN_RSP 78 | 79 | 这个消息用户获取某个用户的登录情况,比如pc登录、安卓版登录还是ios登录,用于某些特殊消息的处理,比如文件发送不会推给移动在线的用户。 80 | 81 | 5. CID_MSG_DATA: 82 | CID_SWITCH_P2P_CMD: 83 | CID_MSG_READ_NOTIFY: 84 | CID_OTHER_SERVER_KICK_USER: 85 | CID_GROUP_CHANGE_MEMBER_NOTIFY: 86 | CID_FILE_NOTIFY: 87 | CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY 88 | 89 | CID_BUDDY_LIST_SIGN_INFO_CHANGED_NOTIFY 90 | 91 | 这几个消息都是往外广播消息,由于msg_server 可以配置多个,A给B发了一条消息,必须广播在各个msg_server 才能知道B到底在哪个msg_server上。 92 | 93 | ```cpp 94 | void CRouteConn::_BroadcastMsg(CImPdu* pPdu, CRouteConn* pFromConn) 95 | { 96 | ConnMap_t::iterator it; 97 | for (it = g_route_conn_map.begin(); it != g_route_conn_map.end(); it++) { 98 | CRouteConn* pRouteConn = (CRouteConn*)it->second; 99 | if (pRouteConn != pFromConn) { 100 | pRouteConn->SendPdu(pPdu); 101 | } 102 | } 103 | } 104 | ``` 105 | 106 | 也就是说CRouteConn代表着到msg_server的连接。 107 | 108 | 109 | 110 | route_server的介绍就这么多了,虽然比较简单,但是这种路由的思想却是非常值得我们学习。网络通信数据包的在不同ip地址的路由最终被送达目的地,也就是这个原理。 -------------------------------------------------------------------------------- /articles/TeamTalk源码解析/10开放一个TeamTalk测试服务器地址和几个测试账号.md: -------------------------------------------------------------------------------- 1 | # 10 开放一个TeamTalk测试服务器地址和几个测试账号 2 | 3 | 由于TeamTalk是用于企业内部的即时通讯软件,一般客户端并不提供账号注册功能。如果你仅对TeamTalk的客户端感兴趣,你可以仅仅研究pc端和移动端代码。官方的测试服务器地址已经失效,所以我已经部署了一套TeamTalk服务器,并建立了几个测试账户可以供你使用: 4 | 5 | tangseng 6 | 7 | sunwukong 8 | 9 | zhubajie 10 | 11 | shaseng 12 | 13 | ================== 14 | 15 | xiaowang 16 | 17 | xiaoming 18 | 19 | xiaozhao 20 | 21 | xiaoli 22 | 23 | ================== 24 | 25 | 以上是账户名,密码随意。我改了下服务器端的代码,密码不进行校验的。你可以填写任意密码。 26 | 27 | pc端设置方式: 28 | 29 | ![](../imgs/tt14.png) 30 | 31 | 32 | 33 | 安卓端设置方式: 34 | 35 | ![](../imgs/tt15.png) 36 | 37 | 38 | 39 | 关于ios端,目前由于服务器端的push_server没有部署,暂且就不提供了。 40 | 41 | 42 | 43 | 我专门把pc端代码和安卓端代码提取出来供大家下载: 44 | 45 | pc端: 46 | 47 | 下载地址:http://download.csdn.net/detail/analogous_love/9851833 48 | 49 | 开发工具:VS2013 50 | 51 | 52 | 53 | 安卓端: 54 | 55 | 下载地址:http://download.csdn.net/detail/analogous_love/9851845 56 | 57 | IDE使用Android-studio 58 | java 1.7 59 | gradle 2.2.1 60 | 61 | > 如果测试服务器连接不上,请通过微信 easy_coder 与我联系。 -------------------------------------------------------------------------------- /articles/TeamTalk源码解析/index.md: -------------------------------------------------------------------------------- 1 | ## TeamTalk源码解析 2 | 3 | * [01 TeamTalk介绍](01TeamTalk介绍.md) 4 | 5 | * [02 服务器端的程序的编译与部署](02服务器端的程序的编译与部署.md) 6 | 7 | * [03 服务器端的程序架构介绍](03服务器端的程序架构介绍.md) 8 | 9 | * [04 服务器端db_proxy_server源码分析](04服务器端db_proxy_server源码分析.md) 10 | 11 | * [05 服务器端msg_server源码分析](05服务器端msg_server源码分析.md) 12 | 13 | * [06 服务器端login_server源码分析](06服务器端login_server源码分析.md) 14 | 15 | * [07 服务器端msfs源码分析](07服务器端msfs源码分析.md) 16 | 17 | * [08 服务器端file_server源码分析](08服务器端file_server源码分析.md) 18 | 19 | * [09 服务器端route_server源码分析](09服务器端route_server源码分析.md) 20 | 21 | * [10 开放一个TeamTalk测试服务器地址和几个测试账号](10开放一个TeamTalk测试服务器地址和几个测试账号.md) 22 | 23 | * [11 pc客户端源码分析](11pc客户端源码分析.md) 24 | 25 | -------------------------------------------------------------------------------- /articles/cppguide-wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/cppguide-wechat.png -------------------------------------------------------------------------------- /articles/imgs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/.DS_Store -------------------------------------------------------------------------------- /articles/imgs/12306-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-1.webp -------------------------------------------------------------------------------- /articles/imgs/12306-10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-10.webp -------------------------------------------------------------------------------- /articles/imgs/12306-11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-11.webp -------------------------------------------------------------------------------- /articles/imgs/12306-12.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-12.jpeg -------------------------------------------------------------------------------- /articles/imgs/12306-13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-13.webp -------------------------------------------------------------------------------- /articles/imgs/12306-14.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-14.webp -------------------------------------------------------------------------------- /articles/imgs/12306-15.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-15.jpeg -------------------------------------------------------------------------------- /articles/imgs/12306-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-2.webp -------------------------------------------------------------------------------- /articles/imgs/12306-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-3.webp -------------------------------------------------------------------------------- /articles/imgs/12306-4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-4.webp -------------------------------------------------------------------------------- /articles/imgs/12306-5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-5.webp -------------------------------------------------------------------------------- /articles/imgs/12306-6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-6.webp -------------------------------------------------------------------------------- /articles/imgs/12306-7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-7.webp -------------------------------------------------------------------------------- /articles/imgs/12306-8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-8.webp -------------------------------------------------------------------------------- /articles/imgs/12306-9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/12306-9.webp -------------------------------------------------------------------------------- /articles/imgs/atomic1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/atomic1.webp -------------------------------------------------------------------------------- /articles/imgs/bz1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/bz1.png -------------------------------------------------------------------------------- /articles/imgs/bz2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/bz2.webp -------------------------------------------------------------------------------- /articles/imgs/cmake1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/cmake1.png -------------------------------------------------------------------------------- /articles/imgs/cmake2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/cmake2.png -------------------------------------------------------------------------------- /articles/imgs/cmake3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/cmake3.png -------------------------------------------------------------------------------- /articles/imgs/cmake4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/cmake4.png -------------------------------------------------------------------------------- /articles/imgs/connect1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect1.png -------------------------------------------------------------------------------- /articles/imgs/connect10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect10.webp -------------------------------------------------------------------------------- /articles/imgs/connect11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect11.png -------------------------------------------------------------------------------- /articles/imgs/connect12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect12.webp -------------------------------------------------------------------------------- /articles/imgs/connect13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect13.webp -------------------------------------------------------------------------------- /articles/imgs/connect2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect2.webp -------------------------------------------------------------------------------- /articles/imgs/connect3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect3.webp -------------------------------------------------------------------------------- /articles/imgs/connect4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect4.webp -------------------------------------------------------------------------------- /articles/imgs/connect5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect5.png -------------------------------------------------------------------------------- /articles/imgs/connect6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect6.webp -------------------------------------------------------------------------------- /articles/imgs/connect7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect7.webp -------------------------------------------------------------------------------- /articles/imgs/connect8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect8.png -------------------------------------------------------------------------------- /articles/imgs/connect9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/connect9.webp -------------------------------------------------------------------------------- /articles/imgs/epoll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/epoll.png -------------------------------------------------------------------------------- /articles/imgs/errorsys1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/errorsys1.png -------------------------------------------------------------------------------- /articles/imgs/game1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game1.webp -------------------------------------------------------------------------------- /articles/imgs/game10.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game10.jpeg -------------------------------------------------------------------------------- /articles/imgs/game11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game11.webp -------------------------------------------------------------------------------- /articles/imgs/game12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game12.webp -------------------------------------------------------------------------------- /articles/imgs/game13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game13.webp -------------------------------------------------------------------------------- /articles/imgs/game14.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game14.webp -------------------------------------------------------------------------------- /articles/imgs/game15.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game15.webp -------------------------------------------------------------------------------- /articles/imgs/game16.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game16.webp -------------------------------------------------------------------------------- /articles/imgs/game17.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game17.webp -------------------------------------------------------------------------------- /articles/imgs/game18.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game18.webp -------------------------------------------------------------------------------- /articles/imgs/game19.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game19.webp -------------------------------------------------------------------------------- /articles/imgs/game2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game2.webp -------------------------------------------------------------------------------- /articles/imgs/game20.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game20.webp -------------------------------------------------------------------------------- /articles/imgs/game21.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game21.webp -------------------------------------------------------------------------------- /articles/imgs/game22.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game22.webp -------------------------------------------------------------------------------- /articles/imgs/game23.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game23.webp -------------------------------------------------------------------------------- /articles/imgs/game24.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game24.webp -------------------------------------------------------------------------------- /articles/imgs/game25.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game25.webp -------------------------------------------------------------------------------- /articles/imgs/game26.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game26.webp -------------------------------------------------------------------------------- /articles/imgs/game27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game27.png -------------------------------------------------------------------------------- /articles/imgs/game28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game28.png -------------------------------------------------------------------------------- /articles/imgs/game29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game29.png -------------------------------------------------------------------------------- /articles/imgs/game3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game3.webp -------------------------------------------------------------------------------- /articles/imgs/game30.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game30.webp -------------------------------------------------------------------------------- /articles/imgs/game31.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game31.webp -------------------------------------------------------------------------------- /articles/imgs/game32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game32.png -------------------------------------------------------------------------------- /articles/imgs/game33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game33.png -------------------------------------------------------------------------------- /articles/imgs/game34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game34.png -------------------------------------------------------------------------------- /articles/imgs/game35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game35.png -------------------------------------------------------------------------------- /articles/imgs/game36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game36.png -------------------------------------------------------------------------------- /articles/imgs/game37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game37.png -------------------------------------------------------------------------------- /articles/imgs/game38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game38.png -------------------------------------------------------------------------------- /articles/imgs/game39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game39.png -------------------------------------------------------------------------------- /articles/imgs/game4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game4.webp -------------------------------------------------------------------------------- /articles/imgs/game40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game40.png -------------------------------------------------------------------------------- /articles/imgs/game41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game41.png -------------------------------------------------------------------------------- /articles/imgs/game42.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game42.webp -------------------------------------------------------------------------------- /articles/imgs/game43.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game43.webp -------------------------------------------------------------------------------- /articles/imgs/game44.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game44.webp -------------------------------------------------------------------------------- /articles/imgs/game45.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game45.webp -------------------------------------------------------------------------------- /articles/imgs/game46.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game46.webp -------------------------------------------------------------------------------- /articles/imgs/game47.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game47.webp -------------------------------------------------------------------------------- /articles/imgs/game48.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game48.webp -------------------------------------------------------------------------------- /articles/imgs/game49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game49.png -------------------------------------------------------------------------------- /articles/imgs/game5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game5.webp -------------------------------------------------------------------------------- /articles/imgs/game50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game50.png -------------------------------------------------------------------------------- /articles/imgs/game51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game51.png -------------------------------------------------------------------------------- /articles/imgs/game52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game52.png -------------------------------------------------------------------------------- /articles/imgs/game53.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game53.webp -------------------------------------------------------------------------------- /articles/imgs/game54.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game54.webp -------------------------------------------------------------------------------- /articles/imgs/game55.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game55.jpeg -------------------------------------------------------------------------------- /articles/imgs/game56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game56.png -------------------------------------------------------------------------------- /articles/imgs/game57.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game57.jpeg -------------------------------------------------------------------------------- /articles/imgs/game58.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game58.webp -------------------------------------------------------------------------------- /articles/imgs/game59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game59.png -------------------------------------------------------------------------------- /articles/imgs/game6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game6.png -------------------------------------------------------------------------------- /articles/imgs/game60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game60.png -------------------------------------------------------------------------------- /articles/imgs/game61.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game61.webp -------------------------------------------------------------------------------- /articles/imgs/game62.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game62.png -------------------------------------------------------------------------------- /articles/imgs/game63.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game63.webp -------------------------------------------------------------------------------- /articles/imgs/game64.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game64.webp -------------------------------------------------------------------------------- /articles/imgs/game65.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game65.jpeg -------------------------------------------------------------------------------- /articles/imgs/game66.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game66.webp -------------------------------------------------------------------------------- /articles/imgs/game67.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game67.webp -------------------------------------------------------------------------------- /articles/imgs/game68.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game68.jpeg -------------------------------------------------------------------------------- /articles/imgs/game69.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game69.webp -------------------------------------------------------------------------------- /articles/imgs/game7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game7.jpeg -------------------------------------------------------------------------------- /articles/imgs/game7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game7.png -------------------------------------------------------------------------------- /articles/imgs/game70.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game70.webp -------------------------------------------------------------------------------- /articles/imgs/game71.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game71.jpeg -------------------------------------------------------------------------------- /articles/imgs/game72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game72.png -------------------------------------------------------------------------------- /articles/imgs/game73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game73.png -------------------------------------------------------------------------------- /articles/imgs/game74.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game74.webp -------------------------------------------------------------------------------- /articles/imgs/game75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game75.png -------------------------------------------------------------------------------- /articles/imgs/game76.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game76.jpeg -------------------------------------------------------------------------------- /articles/imgs/game77.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game77.webp -------------------------------------------------------------------------------- /articles/imgs/game78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game78.png -------------------------------------------------------------------------------- /articles/imgs/game79.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game79.png -------------------------------------------------------------------------------- /articles/imgs/game8.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game8.jpeg -------------------------------------------------------------------------------- /articles/imgs/game80.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game80.jpeg -------------------------------------------------------------------------------- /articles/imgs/game81.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game81.png -------------------------------------------------------------------------------- /articles/imgs/game82.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game82.webp -------------------------------------------------------------------------------- /articles/imgs/game83.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game83.jpeg -------------------------------------------------------------------------------- /articles/imgs/game84.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game84.png -------------------------------------------------------------------------------- /articles/imgs/game85.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game85.webp -------------------------------------------------------------------------------- /articles/imgs/game86.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game86.jpeg -------------------------------------------------------------------------------- /articles/imgs/game87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game87.png -------------------------------------------------------------------------------- /articles/imgs/game88.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game88.webp -------------------------------------------------------------------------------- /articles/imgs/game89.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game89.jpeg -------------------------------------------------------------------------------- /articles/imgs/game9.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game9.jpeg -------------------------------------------------------------------------------- /articles/imgs/game90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game90.png -------------------------------------------------------------------------------- /articles/imgs/game91.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game91.png -------------------------------------------------------------------------------- /articles/imgs/game92.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game92.webp -------------------------------------------------------------------------------- /articles/imgs/game93.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game93.webp -------------------------------------------------------------------------------- /articles/imgs/game94.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game94.jpeg -------------------------------------------------------------------------------- /articles/imgs/game95.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/game95.webp -------------------------------------------------------------------------------- /articles/imgs/http1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/http1.webp -------------------------------------------------------------------------------- /articles/imgs/http2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/http2.webp -------------------------------------------------------------------------------- /articles/imgs/http3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/http3.webp -------------------------------------------------------------------------------- /articles/imgs/http4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/http4.webp -------------------------------------------------------------------------------- /articles/imgs/http5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/http5.webp -------------------------------------------------------------------------------- /articles/imgs/jianli1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli1.png -------------------------------------------------------------------------------- /articles/imgs/jianli2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli2.png -------------------------------------------------------------------------------- /articles/imgs/jianli3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli3.png -------------------------------------------------------------------------------- /articles/imgs/jianli4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli4.png -------------------------------------------------------------------------------- /articles/imgs/jianli5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli5.png -------------------------------------------------------------------------------- /articles/imgs/jianli6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli6.png -------------------------------------------------------------------------------- /articles/imgs/jianli7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli7.png -------------------------------------------------------------------------------- /articles/imgs/jianli8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/jianli8.png -------------------------------------------------------------------------------- /articles/imgs/learningcpp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/learningcpp1.png -------------------------------------------------------------------------------- /articles/imgs/learningcpp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/learningcpp2.png -------------------------------------------------------------------------------- /articles/imgs/learningcpp3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/learningcpp3.png -------------------------------------------------------------------------------- /articles/imgs/learningcpp4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/learningcpp4.png -------------------------------------------------------------------------------- /articles/imgs/learningcpp5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/learningcpp5.png -------------------------------------------------------------------------------- /articles/imgs/learningcpp6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/learningcpp6.png -------------------------------------------------------------------------------- /articles/imgs/learningcpp7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/learningcpp7.png -------------------------------------------------------------------------------- /articles/imgs/leveldb1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb1.png -------------------------------------------------------------------------------- /articles/imgs/leveldb10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb10.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb11.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb12.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb13.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb14.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb14.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb15.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb15.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb16.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb16.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb17.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb17.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb18.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb18.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb19.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb19.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb2.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb20.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb20.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb3.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb4.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb5.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb6.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb7.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb8.webp -------------------------------------------------------------------------------- /articles/imgs/leveldb9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/leveldb9.webp -------------------------------------------------------------------------------- /articles/imgs/libevent1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent1.webp -------------------------------------------------------------------------------- /articles/imgs/libevent10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent10.webp -------------------------------------------------------------------------------- /articles/imgs/libevent11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent11.webp -------------------------------------------------------------------------------- /articles/imgs/libevent12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent12.webp -------------------------------------------------------------------------------- /articles/imgs/libevent2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent2.webp -------------------------------------------------------------------------------- /articles/imgs/libevent3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent3.webp -------------------------------------------------------------------------------- /articles/imgs/libevent4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent4.webp -------------------------------------------------------------------------------- /articles/imgs/libevent5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent5.webp -------------------------------------------------------------------------------- /articles/imgs/libevent6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent6.webp -------------------------------------------------------------------------------- /articles/imgs/libevent7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent7.webp -------------------------------------------------------------------------------- /articles/imgs/libevent8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent8.webp -------------------------------------------------------------------------------- /articles/imgs/libevent9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/libevent9.webp -------------------------------------------------------------------------------- /articles/imgs/log1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/log1.png -------------------------------------------------------------------------------- /articles/imgs/lsof1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/lsof1.jpeg -------------------------------------------------------------------------------- /articles/imgs/lsof2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/lsof2.webp -------------------------------------------------------------------------------- /articles/imgs/mail1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail1.png -------------------------------------------------------------------------------- /articles/imgs/mail2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail2.png -------------------------------------------------------------------------------- /articles/imgs/mail3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail3.png -------------------------------------------------------------------------------- /articles/imgs/mail4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail4.png -------------------------------------------------------------------------------- /articles/imgs/mail5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail5.png -------------------------------------------------------------------------------- /articles/imgs/mail6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail6.png -------------------------------------------------------------------------------- /articles/imgs/mail7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail7.png -------------------------------------------------------------------------------- /articles/imgs/mail8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/mail8.png -------------------------------------------------------------------------------- /articles/imgs/memcached1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/memcached1.webp -------------------------------------------------------------------------------- /articles/imgs/memcached2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/memcached2.webp -------------------------------------------------------------------------------- /articles/imgs/memcached3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/memcached3.webp -------------------------------------------------------------------------------- /articles/imgs/memcached4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/memcached4.webp -------------------------------------------------------------------------------- /articles/imgs/nc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/nc1.png -------------------------------------------------------------------------------- /articles/imgs/nc2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/nc2.jpeg -------------------------------------------------------------------------------- /articles/imgs/nc3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/nc3.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown1.webp -------------------------------------------------------------------------------- /articles/imgs/netdown10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown10.webp -------------------------------------------------------------------------------- /articles/imgs/netdown11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown11.png -------------------------------------------------------------------------------- /articles/imgs/netdown12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown12.webp -------------------------------------------------------------------------------- /articles/imgs/netdown13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown13.png -------------------------------------------------------------------------------- /articles/imgs/netdown14.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown14.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown15.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown15.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown16.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown16.webp -------------------------------------------------------------------------------- /articles/imgs/netdown17.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown17.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown18.png -------------------------------------------------------------------------------- /articles/imgs/netdown19.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown19.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown2.webp -------------------------------------------------------------------------------- /articles/imgs/netdown20.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown20.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown21.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown21.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown22.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown22.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown23.png -------------------------------------------------------------------------------- /articles/imgs/netdown24.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown24.webp -------------------------------------------------------------------------------- /articles/imgs/netdown25.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown25.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown26.png -------------------------------------------------------------------------------- /articles/imgs/netdown27.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown27.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown28.webp -------------------------------------------------------------------------------- /articles/imgs/netdown29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown29.png -------------------------------------------------------------------------------- /articles/imgs/netdown3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown3.png -------------------------------------------------------------------------------- /articles/imgs/netdown4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown4.png -------------------------------------------------------------------------------- /articles/imgs/netdown5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown5.webp -------------------------------------------------------------------------------- /articles/imgs/netdown6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown6.jpeg -------------------------------------------------------------------------------- /articles/imgs/netdown7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown7.webp -------------------------------------------------------------------------------- /articles/imgs/netdown8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown8.webp -------------------------------------------------------------------------------- /articles/imgs/netdown9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/netdown9.webp -------------------------------------------------------------------------------- /articles/imgs/pointer1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer1.webp -------------------------------------------------------------------------------- /articles/imgs/pointer10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer10.webp -------------------------------------------------------------------------------- /articles/imgs/pointer11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer11.webp -------------------------------------------------------------------------------- /articles/imgs/pointer12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer12.webp -------------------------------------------------------------------------------- /articles/imgs/pointer13.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer13.webp -------------------------------------------------------------------------------- /articles/imgs/pointer14.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer14.webp -------------------------------------------------------------------------------- /articles/imgs/pointer15.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer15.webp -------------------------------------------------------------------------------- /articles/imgs/pointer16.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer16.webp -------------------------------------------------------------------------------- /articles/imgs/pointer17.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer17.webp -------------------------------------------------------------------------------- /articles/imgs/pointer18.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer18.webp -------------------------------------------------------------------------------- /articles/imgs/pointer19.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer19.webp -------------------------------------------------------------------------------- /articles/imgs/pointer2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer2.webp -------------------------------------------------------------------------------- /articles/imgs/pointer20.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer20.webp -------------------------------------------------------------------------------- /articles/imgs/pointer21.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer21.webp -------------------------------------------------------------------------------- /articles/imgs/pointer22.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer22.webp -------------------------------------------------------------------------------- /articles/imgs/pointer23.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer23.webp -------------------------------------------------------------------------------- /articles/imgs/pointer24.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer24.webp -------------------------------------------------------------------------------- /articles/imgs/pointer25.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer25.webp -------------------------------------------------------------------------------- /articles/imgs/pointer26.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer26.webp -------------------------------------------------------------------------------- /articles/imgs/pointer27.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer27.webp -------------------------------------------------------------------------------- /articles/imgs/pointer28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer28.webp -------------------------------------------------------------------------------- /articles/imgs/pointer29.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer29.webp -------------------------------------------------------------------------------- /articles/imgs/pointer3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer3.webp -------------------------------------------------------------------------------- /articles/imgs/pointer30.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer30.webp -------------------------------------------------------------------------------- /articles/imgs/pointer31.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer31.webp -------------------------------------------------------------------------------- /articles/imgs/pointer32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer32.webp -------------------------------------------------------------------------------- /articles/imgs/pointer4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer4.webp -------------------------------------------------------------------------------- /articles/imgs/pointer5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer5.webp -------------------------------------------------------------------------------- /articles/imgs/pointer6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer6.webp -------------------------------------------------------------------------------- /articles/imgs/pointer7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer7.webp -------------------------------------------------------------------------------- /articles/imgs/pointer8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer8.webp -------------------------------------------------------------------------------- /articles/imgs/pointer9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/pointer9.webp -------------------------------------------------------------------------------- /articles/imgs/protocol1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol1.webp -------------------------------------------------------------------------------- /articles/imgs/protocol2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol2.webp -------------------------------------------------------------------------------- /articles/imgs/protocol3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol3.webp -------------------------------------------------------------------------------- /articles/imgs/protocol4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol4.webp -------------------------------------------------------------------------------- /articles/imgs/protocol5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol5.webp -------------------------------------------------------------------------------- /articles/imgs/protocol6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol6.jpeg -------------------------------------------------------------------------------- /articles/imgs/protocol7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol7.webp -------------------------------------------------------------------------------- /articles/imgs/protocol8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/protocol8.webp -------------------------------------------------------------------------------- /articles/imgs/reactor1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/reactor1.jpg -------------------------------------------------------------------------------- /articles/imgs/reactor2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/reactor2.jpg -------------------------------------------------------------------------------- /articles/imgs/select1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/select1.webp -------------------------------------------------------------------------------- /articles/imgs/select2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/select2.webp -------------------------------------------------------------------------------- /articles/imgs/select3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/select3.webp -------------------------------------------------------------------------------- /articles/imgs/select4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/select4.webp -------------------------------------------------------------------------------- /articles/imgs/select5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/select5.webp -------------------------------------------------------------------------------- /articles/imgs/select6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/select6.webp -------------------------------------------------------------------------------- /articles/imgs/select7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/select7.webp -------------------------------------------------------------------------------- /articles/imgs/sendrecvreturnvalue1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/sendrecvreturnvalue1.png -------------------------------------------------------------------------------- /articles/imgs/sendrecvreturnvalue2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/sendrecvreturnvalue2.png -------------------------------------------------------------------------------- /articles/imgs/sendway1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/sendway1.webp -------------------------------------------------------------------------------- /articles/imgs/sendway2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/sendway2.webp -------------------------------------------------------------------------------- /articles/imgs/socketmode1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/socketmode1.webp -------------------------------------------------------------------------------- /articles/imgs/socketmode2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/socketmode2.webp -------------------------------------------------------------------------------- /articles/imgs/socketmode3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/socketmode3.webp -------------------------------------------------------------------------------- /articles/imgs/socketmode4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/socketmode4.webp -------------------------------------------------------------------------------- /articles/imgs/sp1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/sp1.webp -------------------------------------------------------------------------------- /articles/imgs/sp2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/sp2.webp -------------------------------------------------------------------------------- /articles/imgs/stack1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/stack1.png -------------------------------------------------------------------------------- /articles/imgs/stack2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/stack2.png -------------------------------------------------------------------------------- /articles/imgs/stack3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/stack3.png -------------------------------------------------------------------------------- /articles/imgs/stack4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/stack4.png -------------------------------------------------------------------------------- /articles/imgs/stack5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/stack5.png -------------------------------------------------------------------------------- /articles/imgs/stack6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/stack6.png -------------------------------------------------------------------------------- /articles/imgs/tcp1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcp1.webp -------------------------------------------------------------------------------- /articles/imgs/tcp2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcp2.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump1.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump10.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump2.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump3.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump4.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump5.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump6.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump7.webp -------------------------------------------------------------------------------- /articles/imgs/tcpdump8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump8.png -------------------------------------------------------------------------------- /articles/imgs/tcpdump9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tcpdump9.png -------------------------------------------------------------------------------- /articles/imgs/telnet1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/telnet1.webp -------------------------------------------------------------------------------- /articles/imgs/telnet2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/telnet2.webp -------------------------------------------------------------------------------- /articles/imgs/telnet3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/telnet3.webp -------------------------------------------------------------------------------- /articles/imgs/telnet4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/telnet4.webp -------------------------------------------------------------------------------- /articles/imgs/tt1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt1.png -------------------------------------------------------------------------------- /articles/imgs/tt10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt10.png -------------------------------------------------------------------------------- /articles/imgs/tt11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt11.jpg -------------------------------------------------------------------------------- /articles/imgs/tt11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt11.png -------------------------------------------------------------------------------- /articles/imgs/tt12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt12.jpg -------------------------------------------------------------------------------- /articles/imgs/tt13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt13.jpg -------------------------------------------------------------------------------- /articles/imgs/tt14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt14.jpg -------------------------------------------------------------------------------- /articles/imgs/tt14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt14.png -------------------------------------------------------------------------------- /articles/imgs/tt15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt15.jpg -------------------------------------------------------------------------------- /articles/imgs/tt15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt15.png -------------------------------------------------------------------------------- /articles/imgs/tt16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt16.jpg -------------------------------------------------------------------------------- /articles/imgs/tt16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt16.png -------------------------------------------------------------------------------- /articles/imgs/tt17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt17.png -------------------------------------------------------------------------------- /articles/imgs/tt18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt18.png -------------------------------------------------------------------------------- /articles/imgs/tt19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt19.png -------------------------------------------------------------------------------- /articles/imgs/tt2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt2.png -------------------------------------------------------------------------------- /articles/imgs/tt20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt20.png -------------------------------------------------------------------------------- /articles/imgs/tt21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt21.png -------------------------------------------------------------------------------- /articles/imgs/tt22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt22.png -------------------------------------------------------------------------------- /articles/imgs/tt23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt23.png -------------------------------------------------------------------------------- /articles/imgs/tt24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt24.png -------------------------------------------------------------------------------- /articles/imgs/tt25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt25.png -------------------------------------------------------------------------------- /articles/imgs/tt26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt26.png -------------------------------------------------------------------------------- /articles/imgs/tt27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt27.png -------------------------------------------------------------------------------- /articles/imgs/tt28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt28.png -------------------------------------------------------------------------------- /articles/imgs/tt29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt29.png -------------------------------------------------------------------------------- /articles/imgs/tt3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt3.png -------------------------------------------------------------------------------- /articles/imgs/tt30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt30.png -------------------------------------------------------------------------------- /articles/imgs/tt31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt31.png -------------------------------------------------------------------------------- /articles/imgs/tt32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt32.png -------------------------------------------------------------------------------- /articles/imgs/tt33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt33.png -------------------------------------------------------------------------------- /articles/imgs/tt4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt4.png -------------------------------------------------------------------------------- /articles/imgs/tt5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt5.png -------------------------------------------------------------------------------- /articles/imgs/tt6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt6.png -------------------------------------------------------------------------------- /articles/imgs/tt7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt7.jpeg -------------------------------------------------------------------------------- /articles/imgs/tt8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt8.png -------------------------------------------------------------------------------- /articles/imgs/tt9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/tt9.png -------------------------------------------------------------------------------- /articles/imgs/vargs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vargs.png -------------------------------------------------------------------------------- /articles/imgs/vs1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vs1.png -------------------------------------------------------------------------------- /articles/imgs/vs2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vs2.png -------------------------------------------------------------------------------- /articles/imgs/vs3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vs3.png -------------------------------------------------------------------------------- /articles/imgs/vs4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vs4.png -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux1.webp -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux10.webp -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux2.jpeg -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux3.webp -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux4.webp -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux5.webp -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux6.webp -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux7.jpeg -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux8.webp -------------------------------------------------------------------------------- /articles/imgs/vsdebuglinux9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/vsdebuglinux9.webp -------------------------------------------------------------------------------- /articles/imgs/websocket1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/websocket1.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz1.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz10.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz10.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz11.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz12.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz13.png -------------------------------------------------------------------------------- /articles/imgs/zhyz14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz14.png -------------------------------------------------------------------------------- /articles/imgs/zhyz15.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz15.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz16.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz16.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz17.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz17.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz18.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz18.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz19.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz19.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz2.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz20.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz20.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz21.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz21.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz22.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz22.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz23.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz23.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz24.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz24.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz25.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz25.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz26.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz26.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz27.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz27.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz28.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz29.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz29.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz3.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz30.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz30.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz31.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz31.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz32.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz33.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz33.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz34.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz34.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz35.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz35.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz36.png -------------------------------------------------------------------------------- /articles/imgs/zhyz37.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz37.jpeg -------------------------------------------------------------------------------- /articles/imgs/zhyz38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz38.png -------------------------------------------------------------------------------- /articles/imgs/zhyz39.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz39.jpeg -------------------------------------------------------------------------------- /articles/imgs/zhyz4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz4.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz40.png -------------------------------------------------------------------------------- /articles/imgs/zhyz41.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz41.jpeg -------------------------------------------------------------------------------- /articles/imgs/zhyz42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz42.png -------------------------------------------------------------------------------- /articles/imgs/zhyz43.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz43.jpeg -------------------------------------------------------------------------------- /articles/imgs/zhyz44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz44.png -------------------------------------------------------------------------------- /articles/imgs/zhyz45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz45.png -------------------------------------------------------------------------------- /articles/imgs/zhyz46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz46.png -------------------------------------------------------------------------------- /articles/imgs/zhyz47.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz47.jpeg -------------------------------------------------------------------------------- /articles/imgs/zhyz48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz48.png -------------------------------------------------------------------------------- /articles/imgs/zhyz49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz49.png -------------------------------------------------------------------------------- /articles/imgs/zhyz5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz5.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz6.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz7.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz8.webp -------------------------------------------------------------------------------- /articles/imgs/zhyz9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/imgs/zhyz9.webp -------------------------------------------------------------------------------- /articles/leveldb源码分析/README.md: -------------------------------------------------------------------------------- 1 | ## leveldb源码分析 2 | 3 | * [leveldb源码分析1](leveldb源码分析1.md) 4 | 5 | * [leveldb源码分析2](leveldb源码分析2.md) 6 | 7 | * [leveldb源码分析3](leveldb源码分析3.md) 8 | 9 | * [leveldb源码分析4](leveldb源码分析4.md) 10 | 11 | * [leveldb源码分析5](leveldb源码分析5.md) 12 | 13 | * [leveldb源码分析6](leveldb源码分析6.md) 14 | 15 | * [leveldb源码分析7](leveldb源码分析7.md) 16 | 17 | * [leveldb源码分析8](leveldb源码分析8.md) 18 | 19 | * [leveldb源码分析9](leveldb源码分析9.md) 20 | 21 | * [leveldb源码分析10](leveldb源码分析10.md) 22 | 23 | * [leveldb源码分析11](leveldb源码分析11.md) 24 | 25 | * [leveldb源码分析12](leveldb源码分析12.md) 26 | 27 | * [leveldb源码分析13](leveldb源码分析13.md) 28 | 29 | * [leveldb源码分析14](leveldb源码分析14.md) 30 | 31 | * [leveldb源码分析15](leveldb源码分析15.md) 32 | 33 | * [leveldb源码分析16](leveldb源码分析16.md) 34 | 35 | * [leveldb源码分析17](leveldb源码分析17.md) 36 | 37 | * [leveldb源码分析18](leveldb源码分析18.md) 38 | 39 | * [leveldb源码分析19](leveldb源码分析19.md) 40 | 41 | * [leveldb源码分析20](leveldb源码分析20.md) 42 | 43 | * [leveldb源码分析21](leveldb源码分析21.md) 44 | 45 | * [leveldb源码分析22](leveldb源码分析22.md) -------------------------------------------------------------------------------- /articles/leveldb源码分析/leveldb源码分析2.md: -------------------------------------------------------------------------------- 1 | # leveldb源码分析2 2 | 3 | 本系列《leveldb源码分析》共有22篇文章,这是第二篇。 4 | 5 | ### 3.Int Coding 6 | 7 | 轻松一刻,前面约定中讲过Leveldb使用了很多VarInt型编码,典型的如后面将涉及到的各种key。其中的**编码、解码函数分为VarInt和FixedInt两种**。int32和int64操作都是类似的。 8 | 9 | #### 3.1 Eecode 10 | 11 | 首先是**FixedInt编码**,直接上代码,很简单明了。 12 | 13 | ``` 14 | void EncodeFixed32(char* buf, uint32_t value) 15 | { 16 | if (port::kLittleEndian) { 17 | memcpy(buf, &value,sizeof(value)); 18 | } else { 19 | buf[0] = value & 0xff; 20 | buf[1] = (value >> 8)& 0xff; 21 | buf[2] = (value >> 16)& 0xff; 22 | buf[3] = (value >> 24)& 0xff; 23 | } 24 | } 25 | ``` 26 | 27 | 下面是**VarInt编码**,int32和int64格式,代码如下,有效位是7bit的,因此把uint32按7bit分割,对unsigned char赋值时,超出0xFF会自动截断,因此直接*(ptr++) = v|B即可,不需要再把(v|B)与0xFF作&操作。 28 | 29 | ``` 30 | char* EncodeVarint32(char* dst, uint32_t v) 31 | { 32 | unsigned char* ptr =reinterpret_cast(dst); 33 | static const int B = 128; 34 | if (v < (1<<7)) { 35 | *(ptr++) = v; 36 | } else if (v < (1<<14)){ 37 | *(ptr++) = v | B; 38 | *(ptr++) = v>>7; 39 | } else if (v < (1<<21)){ 40 | *(ptr++) = v | B; 41 | *(ptr++) = (v>>7) | B; 42 | *(ptr++) = v>>14; 43 | } else if (v < (1<<28)){ 44 | *(ptr++) = v | B; 45 | *(ptr++) = (v>>7) | B; 46 | *(ptr++) = (v>>14) | B; 47 | *(ptr++) = v>>21; 48 | } else { 49 | *(ptr++) = v | B; 50 | *(ptr++) = (v>>7) | B; 51 | *(ptr++) = (v>>14) | B; 52 | *(ptr++) = (v>>21) | B; 53 | *(ptr++) = v>>28; 54 | } 55 | return reinterpret_cast(ptr); 56 | } 57 | 58 | // 对于uint64,直接循环 59 | char* EncodeVarint64(char* dst, uint64_t v) { 60 | static const int B = 128; 61 | unsigned char* ptr =reinterpret_cast(dst); 62 | while (v >= B) { 63 | *(ptr++) = (v & (B-1)) |B; 64 | v >>= 7; 65 | } 66 | *(ptr++) =static_cast(v); 67 | returnreinterpret_cast(ptr); 68 | } 69 | ``` 70 | 71 | #### 3.2 Decode 72 | 73 | **Fixed Int的Decode**,操作,代码: 74 | 75 | ``` 76 | inline uint32_t DecodeFixed32(const char* ptr) 77 | { 78 | if (port::kLittleEndian) { 79 | uint32_t result; 80 | // gcc optimizes this to a plain load 81 | memcpy(&result, ptr,sizeof(result)); 82 | return result; 83 | } else { 84 | return((static_cast(static_cast(ptr[0]))) 85 | |(static_cast(static_cast(ptr[1])) <<8) 86 | | (static_cast(static_cast(ptr[2])) << 16) 87 | |(static_cast(static_cast(ptr[3])) <<24)); 88 | } 89 | } 90 | ``` 91 | 92 | 再来看看**VarInt的解码**,很简单,依次读取1byte,直到最高位为0的byte结束,取低7bit,作(<<7)移位操作组合成Int。看代码: 93 | 94 | ``` 95 | const char* GetVarint32Ptr(const char* p, 96 | const char* limit, 97 | uint32_t* value) 98 | { 99 | if (p < limit) { 100 | uint32_t result =*(reinterpret_cast(p)); 101 | if ((result & 128) == 0) { 102 | *value = result; 103 | return p + 1; 104 | } 105 | } 106 | return GetVarint32PtrFallback(p,limit, value); 107 | } 108 | 109 | const char* GetVarint32PtrFallback(const char* p, 110 | const char* limit, 111 | uint32_t* value) 112 | { 113 | uint32_t result = 0; 114 | for (uint32_t shift = 0; shift<= 28 && p < limit; shift += 7) { 115 | uint32_t byte =*(reinterpret_cast(p)); 116 | p++; 117 | if (byte & 128) { // More bytes are present 118 | result |= ((byte & 127)<< shift); 119 | } else { 120 | result |= (byte <(p); 123 | } 124 | } 125 | return NULL; 126 | } 127 | ``` 128 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/index.md: -------------------------------------------------------------------------------- 1 | ## libevent源码深度剖析 2 | 3 | * [libevent源码深度剖析01](libevent源码深度剖析01.md) 4 | 5 | * [libevent源码深度剖析02](libevent源码深度剖析02.md) 6 | 7 | * [libevent源码深度剖析03](libevent源码深度剖析03.md) 8 | 9 | * [libevent源码深度剖析04](libevent源码深度剖析04.md) 10 | 11 | * [libevent源码深度剖析05](libevent源码深度剖析05.md) 12 | 13 | * [libevent源码深度剖析06](libevent源码深度剖析06.md) 14 | 15 | * [libevent源码深度剖析07](libevent源码深度剖析07.md) 16 | 17 | * [libevent源码深度剖析08](libevent源码深度剖析08.md) 18 | 19 | * [libevent源码深度剖析09](libevent源码深度剖析09.md) 20 | 21 | * [libevent源码深度剖析10](libevent源码深度剖析10.md) 22 | 23 | * [libevent源码深度剖析11](libevent源码深度剖析11.md) 24 | 25 | * [libevent源码深度剖析12](libevent源码深度剖析12.md) 26 | 27 | * [libevent源码深度剖析13](libevent源码深度剖析13.md) -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析01.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析一 2 | 3 | ### 1. 前言 4 | 5 | libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少。写这一系列文章的用意在于,一则分享心得;二则对libevent代码和设计思想做系统的、更深层次的分析,写出来,也可供后来者参考。 6 | 7 | 附带一句:libevent是用**c语言**编写的(大牛们都偏爱c语言哪),而且几乎是无处不函数指针,学习其源代码也需要相当的c语言基础。 8 | 9 | ### 2. Libevent简介 10 | 11 | 上来当然要先夸奖啦,libevent 有几个显著的亮点: 12 | 事件驱动(event-driven),高性能; 13 | 轻量级,专注于网络,不如ACE那么臃肿庞大; 14 | 源代码相当精炼、易读; 15 | 跨平台,支持Windows、Linux、BSD和Mac Os; 16 | 支持多种I/O多路复用技术, epoll、poll、dev/poll、select和kqueue等; 17 | 支持I/O,定时器和信号等事件; 18 | 注册事件优先级; 19 | 20 | libevent已经被广泛的应用,作为底层的网络库;比如memcached、Vomit、Nylon、Netchat等等。 21 | libevent当前的最新稳定版是1.4.13;这也是本文参照的版本。 22 | 23 | ### 3. 学习的好处 24 | 25 | 学习libevent有助于提升程序设计功力,除了网络程序设计方面外,libevent的代码里有很多有用的设计技巧和基础数据结构,比如信息隐藏、函数指针、c语言的多态支持、链表和堆等等,都有助于提升自身的程序功力。 26 | 程序设计不止要了解框架,很多细节之处恰恰也是事关整个系统成败的关键。只对libevent本身的框架大概了解,那或许仅仅是一知半解,不深入代码分析,就难以了解其设计的精巧之处,也就难以为自己所用。 27 | 28 | 事实上libevent本身就是一个典型的**Reactor**模型,理解Reactor模式是理解libevent的基石;因此下一节将介绍典型的事件驱动设计模式——Reactor模式。 29 | 30 | 参考资料: 31 | libevent官方地址: http://monkey.org/~provos/libevent/ 32 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析02.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析02 2 | 3 | Reactor模式 4 | 5 | 前面讲到,整个libevent本身就是一个**Reactor**,因此本节将专门对Reactor模式进行必要的介绍,并列出libevent中的几个重要组件和Reactor的对应关系,在后面的章节中可能还会提到本节介绍的基本概念。 6 | 7 | 8 | 9 | ### 1. Reactor的事件处理机制 10 | 11 | 首先来回想一下普通函数调用的机制:程序调用某函数?函数执行,程序等待?函数将结果和控制权返回给程序?程序继续处理。 12 | 13 | Reactor释义**“反应堆”**,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个**API**完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的事件发生,Reactor将主动调用应用程序注册的接口,这些接口又称为**“回调函数”**。使用libevent也是想libevent框架注册相应的事件和回调函数;当这些事件发生时,libevent会调用这些回调函数处理相应的事件(I/O读写、定时和信号)。 14 | 15 | 用“好莱坞原则”来形容Reactor再合适不过了:不要打电话给我们,我们会打电话通知你。 16 | 17 | 举个例子:你去应聘某xx公司,面试结束后。 18 | 19 | “普通函数调用机制”公司HR比较懒,不会记你的联系方式,那怎么办呢,你只能面试完后自己打电话去问结果;有没有被录取啊,还是被据了; 20 | 21 | “Reactor”公司HR就记下了你的联系方式,结果出来后会主动打电话通知你:有没有被录取啊,还是被据了;你不用自己打电话去问结果,事实上也不能,你没有HR的留联系方式。 22 | 23 | 24 | 25 | ### 2. Reactor模式的优点 26 | 27 | Reactor模式是编写高性能网络服务器的必备技术之一,它具有如下的优点 28 | 29 | 1)响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的; 30 | 31 | 2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销; 32 | 3)可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源; 33 | 4)可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性; 34 | 35 | ### 3. Reactor模式框架 36 | 37 | 使用Reactor模型,必备的几个组件:**事件源**、**Reactor框架**、**多路复用机制和事件处理程序**,先来看看Reactor模型的整体框架,接下来再对每个组件做逐一说明。 38 | 39 | ![](../imgs/libevent1.webp) 40 | 41 | 42 | 43 | 1) 事件源 44 | Linux上是文件描述符,Windows上就是**Socket**或者**Handle**了,这里统一称为“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O事件。 45 | 46 | 2) event demultiplexer——事件多路分发机制 47 | 由操作系统提供的I/O多路复用机制,比如**select**和**epoll**。 48 | 程序首先将其关心的句柄(事件源)及其事件注册到**event demultiplexer**上; 49 | 当有事件到达时,event demultiplexer会发出通知“在已经注册的句柄集中,一个或多个句柄的事件已经就绪”; 50 | 程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。 51 | 对应到libevent中,依然是select、poll、epoll等,但是libevent使用结构体**eventop**进行了封装,以统一的接口来支持这些I/O多路复用机制,达到了对外隐藏底层系统机制的目的。 52 | 53 | 3) Reactor——反应器 54 | Reactor,是事件管理的接口,内部使用**event demultiplexer**注册、注销事件;并运行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。 55 | 对应到libevent中,就是**event_base**结构体。 56 | 一个典型的Reactor声明方式: 57 | 58 | ``` 59 | class Reactor{ 60 | public: 61 | int register_handler(Event_Handler *pHandler, int event); 62 | int remove_handler(Event_Handler *pHandler, int event); 63 | void handle_events(timeval *ptv); 64 | // ... 65 | }; 66 | ``` 67 | 68 | 69 | 70 | 4) Event Handler——事件处理程序 71 | 72 | 事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供Reactor在相应的事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。 73 | 对应到libevent中,就是event结构体。 74 | 下面是两种典型的Event Handler类声明方式,二者互有优缺点。 75 | 76 | ``` 77 | class Event_Handler{ 78 | public: 79 | virtual void handle_read() = 0; 80 | virtual void handle_write() = 0; 81 | virtual void handle_timeout() = 0; 82 | virtual void handle_close() = 0; 83 | virtual HANDLE get_handle() = 0; 84 | // ... 85 | }; 86 | 87 | class Event_Handler{ 88 | public: 89 | // events maybe read/write/timeout/close .etc 90 | virtual void handle_events(int events) = 0; 91 | virtual HANDLE get_handle() = 0; 92 | // ... 93 | }; 94 | ``` 95 | 96 | ### 97 | 98 | ### 4. Reactor事件处理流程 99 | 100 | 前面说过Reactor将事件流“逆置”了,那么使用Reactor模式后,事件控制流是什么样子呢? 101 | 可以参见下面的序列图。 102 | 103 | ![](../imgs/libevent2.webp) 104 | 105 | 106 | 107 | ### 5. 小结 108 | 109 | 上面讲到了Reactor的基本概念、框架和处理流程,对Reactor有个基本清晰的了解后,再来对比看libevent就会更容易理解了,接下来就正式进入到libevent的代码世界了,加油! 110 | 111 | 112 | 113 | 参考资料: 114 | Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects, Volume 2 115 | 116 | 117 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析03.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析03 2 | 3 | ### libevent基本使用场景和事件流程 4 | 5 | ### 1. 前言 6 | 7 | 学习源代码该从哪里入手?我觉得从程序的基本使用场景和代码的整体处理流程入手是个不错的方法,至少从个人的经验上讲,用此方法分析libevent是比较有效的。 8 | 9 | ### 2. 基本应用场景 10 | 11 | 基本应用场景也是使用libevnet的基本流程,下面来考虑一个最简单的场景,使用livevent设置定时器,应用程序只需要执行下面几个简单的步骤即可。 12 | 1)首先初始化libevent库,并保存返回的指针 13 | 14 | ``` 15 | struct event_base* base = event_init(); 16 | ``` 17 | 18 | 实际上这一步相当于初始化一个Reactor实例;在初始化libevent后,就可以注册事件了。 19 | 20 | 2)初始化事件event,设置回调函数和关注的事件 21 | 22 | ``` 23 | evtimer_set(&ev, timer_cb, NULL); 24 | ``` 25 | 26 | 事实上这等价于调用 `event_set(&ev, -1, 0, timer_cb, NULL);` 27 | event_set的函数原型是: 28 | 29 | ``` 30 | void event_set(struct event *ev, int fd, short event, void (*cb)(int, short, void *), void *arg) 31 | ``` 32 | 33 | ev:执行要初始化的event对象; 34 | fd:该event绑定的“句柄”,对于信号事件,它就是关注的信号; 35 | event:在该fd上关注的事件类型,它可以是**EV_READ, EV_WRITE, EV_SIGNAL**; 36 | cb:这是一个函数指针,当fd上的事件event发生时,调用该函数执行处理,它有三个参数,调用时由**event_base**负责传入,按顺序,实际上就是event_set时的fd, event和arg; 37 | arg:传递给cb函数指针的参数; 38 | 由于定时事件不需要fd,并且定时事件是根据添加时**(event_add)**的超时值设定的,因此这里event也不需要设置。 39 | 这一步相当于初始化一个**event handler**,在libevent中事件类型保存在event结构体中。 40 | 注意:libevent并不会管理event事件集合,这需要应用程序自行管理; 41 | 42 | 3)设置event从属的event_base 43 | 44 | ``` 45 | event_base_set(base, &ev); 46 | ``` 47 | 48 | 这一步相当于指明event要注册到哪个event_base实例上; 49 | 50 | 4)是正式的添加事件的时候了 51 | 52 | ``` 53 | event_add(&ev, timeout); 54 | ``` 55 | 56 | 基本信息都已设置完成,只要简单的调用**event_add()**函数即可完成,其中timeout是定时值; 57 | 这一步相当于调用**Reactor::register_handler()**函数注册事件。 58 | 59 | 5)程序进入无限循环,等待就绪事件并执行事件处理 60 | 61 | ``` 62 | event_base_dispatch(base); 63 | ``` 64 | 65 | ### 3. 实例代码 66 | 67 | 上面例子的程序代码如下所示 68 | 69 | ``` 70 | struct event ev; 71 | struct timeval tv; 72 | void time_cb(int fd, short event, void *argc){ 73 | printf("timer wakeup/n"); 74 | event_add(&ev, &tv); // reschedule timer 75 | } 76 | 77 | int main(){ 78 | struct event_base *base = event_init(); 79 | tv.tv_sec = 10; // 10s period 80 | tv.tv_usec = 0; 81 | evtimer_set(&ev, time_cb, NULL); 82 | event_add(&ev, &tv); 83 | event_base_dispatch(base); 84 | } 85 | ``` 86 | 87 | ### 4. 事件处理流程 88 | 89 | 当应用程序向libevent注册一个事件后,libevent内部是怎么样进行处理的呢?下面的图就给出了这一基本流程。 90 | 1)首先应用程序准备并初始化event,设置好事件类型和回调函数;这对应于前面第步骤2和3; 91 | 2)向libevent添加该事件event。对于定时事件,libevent使用一个小根堆管理,key为超时时间;对于Signal和I/O事件,libevent将其放入到等待链表(wait list)中,这是一个双向链表结构; 92 | 3)程序调用**event_base_dispatch()**系列函数进入无限循环,等待事件,以select()函数为例;每次循环前libevent会检查定时事件的最小超时时间tv,根据tv设置select()的最大等待时间,以便于后面及时处理超时事件; 93 | 当select()返回后,首先检查超时事件,然后检查I/O事件; 94 | Libevent将所有的就绪事件,放入到激活链表中; 95 | 然后对激活链表中的事件,调用事件的回调函数执行事件处理; 96 | ![](../imgs/libevent3.webp) 97 | 98 | ### 5. 小结 99 | 100 | 本节介绍了libevent的简单实用场景,并旋风般的介绍了libevent的事件处理流程,读者应该对libevent有了基本的印象,下面将会详细介绍libevent的事件管理框架(Reactor模式中的Reactor框架)做详细的介绍,在此之前会对源代码文件做简单的分类。 101 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析04.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析04 2 | 3 | ### 1. 前言 4 | 5 | 详细分析源代码之前,如果能对其代码文件的基本结构有个大概的认识和分类,对于代码的分析将是大有裨益的。本节内容不多,我想并不是说它不重要! 6 | 7 | ### 2. 源代码组织结构 8 | 9 | Libevent的源代码虽然都在一层文件夹下面,但是其代码分类还是相当清晰的,主要可分为头文件、内部使用的头文件、辅助功能函数、日志、libevent框架、对系统I/O多路复用机制的封装、信号管理、定时事件管理、缓冲区管理、基本数据结构和基于libevent的两个实用库等几个部分,有些部分可能就是一个源文件。 10 | 源代码中的test部分就不在我们关注的范畴了。 11 | 1)头文件 12 | 主要就是**event.h**:事件宏定义、接口函数声明,主要结构体event的声明; 13 | 2)内部头文件 14 | **xxx-internal.h**:内部数据结构和函数,对外不可见,以达到信息隐藏的目的; 15 | 3)libevent框架 16 | **event.c**:event整体框架的代码实现; 17 | 4)对系统I/O多路复用机制的封装 18 | **epoll.c**:对epoll的封装; 19 | **select.c**:对select的封装; 20 | **devpoll.c**:对dev/poll的封装; 21 | **kqueue.c**:对kqueue的封装; 22 | 5)定时事件管理 23 | **min-heap.h**:其实就是一个以时间作为key的小根堆结构; 24 | 6)信号管理 25 | **signal.c**:对信号事件的处理; 26 | 7)辅助功能函数 27 | **evutil.h** 和**evutil.c**:一些辅助功能函数,包括创建socket pair和一些时间操作函数:加、减和比较等。 28 | 8)日志 29 | **log.h**和**log.c**:log日志函数 30 | 9)缓冲区管理 31 | **evbuffer.c**和**buffer.c**:libevent对缓冲区的封装; 32 | 10)基本数据结构 33 | **compat/sys**下的两个源文件:queue.h是libevent基本数据结构的实现,包括链表,双向链表,队列等;_libevent_time.h:一些用于时间操作的结构体定义、函数和宏定义; 34 | 11)实用网络库 35 | **http**和**evdns**:是基于libevent实现的http服务器和异步dns查询库; 36 | 37 | ### 3. 小结 38 | 39 | 本节介绍了libevent的组织和分类,下面将会详细介绍libevent的核心部分event结构。 40 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析08.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析08 2 | 3 | **集成信号处理** 4 | 5 | 现在我们已经了解了libevent的基本框架:事件管理框架和事件主循环。上节提到了libevent中I/O事件和Signal以及Timer事件的集成,这一节将分析如何将**Signal**集成到事件主循环的框架中。 6 | 7 | ### 1. 集成策略——使用socket pair 8 | 9 | 前一节已经做了足够多的介绍了,基本方法就是采用“消息机制”。在libevent中这是通过socket pair完成的,下面就来详细分析一下。 10 | Socket pair就是一个socket对,包含两个socket,一个读socket,一个写socket。工作方式如下图所示: 11 | 12 | ![](../imgs/libevent6.webp) 13 | 14 | 创建一个socket pair并不是复杂的操作,可以参见下面的流程图,清晰起见,其中忽略了一些错误处理和检查。 15 | 16 | ![](../imgs/libevent7.webp) 17 | 18 | Libevent提供了辅助函数**evutil_socketpair()**来创建一个**socket pair**,可以结合上面的创建流程来分析该函数。 19 | 20 | ### 2. 集成到事件主循环——通知event_base 21 | 22 | Socket pair创建好了,可是libevent的事件主循环还是不知道Signal是否发生了啊,看来我们还差了最后一步,那就是:为socket pair的读socket在libevent的**event_base**实例上注册一个**persist**的读事件。 23 | 这样当向写socket写入数据时,读socket就会得到通知,触发读事件,从而event_base就能相应的得到通知了。 24 | 前面提到过,Libevent会在事件主循环中检查标记,来确定是否有触发的signal,如果标记被设置就处理这些signal,这段代码在各个具体的I/O机制中,以Epoll为例,在**epoll_dispatch()**函数中,代码片段如下: 25 | 26 | ``` 27 | res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); 28 | if (res == -1) { 29 | if (errno != EINTR) { 30 | event_warn("epoll_wait"); 31 | return (-1); 32 | } 33 | evsignal_process(base);// 处理signal事件 34 | return (0); 35 | } else if (base->sig.evsignal_caught) { 36 | evsignal_process(base);// 处理signal事件 37 | } 38 | ``` 39 | 40 | 完整的处理框架如下所示: 41 | 42 | ![](../imgs/libevent8.webp) 43 | 44 | 注1:libevent中,初始化阶段并不注册读socket的读事件,而是在注册信号阶段才会测试并注册; 45 | 注2:libevent中,检查I/O事件是在各系统I/O机制的**dispatch()**函数中完成的,该dispatch()函数在**event_base_loop()**函数中被调用; 46 | 47 | ### 3. evsignal_info结构体 48 | 49 | libevent中Signal事件的管理是通过结构体**evsignal_info**完成的,结构体位于evsignal.h文件中,定义如下: 50 | 51 | ``` 52 | struct evsignal_info { 53 | struct event ev_signal; 54 | int ev_signal_pair[2]; 55 | int ev_signal_added; 56 | volatile sig_atomic_t evsignal_caught; 57 | struct event_list evsigevents[NSIG]; 58 | sig_atomic_t evsigcaught[NSIG]; 59 | #ifdef HAVE_SIGACTION 60 | struct sigaction **sh_old; 61 | #else 62 | ev_sighandler_t **sh_old; 63 | #endif 64 | int sh_old_max; 65 | }; 66 | ``` 67 | 68 | 下面详细介绍一下个字段的含义和作用: 69 | 1)ev_signal, 为socket pair的读socket向event_base注册读事件时使用的event结构体; 70 | 2)ev_signal_pair,socket pair对,作用见第一节的介绍; 71 | 3)ev_signal_added,记录ev_signal事件是否已经注册了; 72 | 4)evsignal_caught,是否有信号发生的标记;是volatile类型,因为它会在另外的线程中被修改; 73 | 5)evsigvents[NSIG],数组,evsigevents[signo]表示注册到信号signo的事件链表; 74 | 6)evsigcaught[NSIG],具体记录每个信号触发的次数,evsigcaught[signo]是记录信号signo被触发的次数; 75 | 7)sh_old记录了原来的signal处理函数指针,当信号signo注册的event被清空时,需要重新设置其处理函数; 76 | evsignal_info的初始化包括,创建socket pair,设置ev_signal事件(但并没有注册,而是等到有信号注册时才检查并注册),并将所有标记置零,初始化信号的注册事件链表指针等。 77 | 78 | ### 4. 注册、注销signal事件 79 | 80 | 注册signal事件是通过**evsignal_add(struct event \*ev)**函数完成的,libevent对所有的信号注册同一个处理函数**evsignal_handler()**,该函数将在下一段介绍,注册过程如下: 81 | 1 取得ev要注册到的信号**signo**; 82 | 2 如果信号signo未被注册,那么就为signo注册信号处理函数**evsignal_handler()**; 83 | 3 如果事件ev_signal还没哟注册,就注册**ev_signal**事件; 84 | 4 将事件ev添加到signo的**event**链表中; 85 | 从signo上注销一个已注册的signal事件就更简单了,直接从其已注册事件的链表中移除即可。如果事件链表已空,那么就恢复旧的处理函数; 86 | 下面的讲解都以signal()函数为例,sigaction()函数的处理和signal()相似。 87 | 处理函数evsignal_handler()函数做的事情很简单,就是记录信号的发生次数,并通知event_base有信号触发,需要处理: 88 | 89 | ``` 90 | static void evsignal_handler(int sig){ 91 | int save_errno = errno; // 不覆盖原来的错误代码 92 | if (evsignal_base == NULL) { 93 | event_warn("%s: received signal %d, but have no base configured", __func__, sig); 94 | return; 95 | } 96 | // 记录信号sig的触发次数,并设置event触发标记 97 | evsignal_base->sig.evsigcaught[sig]++; 98 | evsignal_base->sig.evsignal_caught = 1; 99 | #ifndef HAVE_SIGACTION 100 | signal(sig, evsignal_handler); // 重新注册信号 101 | #endif 102 | // 向写socket写一个字节数据,触发event_base的I/O事件,从而通知其有信号触发,需要处理 103 | send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); 104 | errno = save_errno; // 错误代码 105 | } 106 | ``` 107 | 108 | 109 | 110 | ### 5. 小节 111 | 112 | 本节介绍了libevent对signal事件的具体处理框架,包括事件注册、删除和socket pair通知机制,以及是如何将Signal事件集成到事件主循环之中的。 -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析09.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析09 2 | 3 | **集成定时器事件** 4 | 5 | 现在再来详细分析libevent中I/O事件和Timer事件的集成,与Signal相比,Timer事件的集成会直观和简单很多。Libevent对堆的调整操作做了一些优化,本节还会描述这些优化方法。 6 | 7 | ### 1. 集成到事件主循环 8 | 9 | 因为系统的I/O机制像select()和epoll_wait()都允许程序制定一个最大等待时间(也称为最大超时时间)**timeout**,即使没有I/O事件发生,它们也保证能在timeout时间内返回。 10 | 那么根据所有Timer事件的最小超时时间来设置系统I/O的timeout时间;当系统I/O返回时,再激活所有就绪的Timer事件就可以了,这样就能将Timer事件完美的融合到系统的I/O机制中了。 11 | 具体的代码在源文件event.c的**event_base_loop()**中,现在就对比代码来看看这一处理方法: 12 | 13 | ``` 14 | if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) { 15 | // 根据Timer事件计算evsel->dispatch的最大等待时间 16 | timeout_next(base, &tv_p); 17 | } else { 18 | // 如果还有活动事件,就不要等待,让evsel->dispatch立即返回 19 | evutil_timerclear(&tv); 20 | } 21 | // ... 22 | // 调用select() or epoll_wait() 等待就绪I/O事件 23 | res = evsel->dispatch(base, evbase, tv_p); 24 | // ... 25 | // 处理超时事件,将超时事件插入到激活链表中 26 | timeout_process(base); 27 | ``` 28 | 29 | **timeout_next()**函数根据堆中具有最小超时值的事件和当前时间来计算等待时间,下面看看代码: 30 | 31 | ``` 32 | 1static int timeout_next(struct event_base *base, struct timeval **tv_p){ 33 | 2 struct timeval now; 34 | 3 struct event *ev; 35 | 4 struct timeval *tv = *tv_p; 36 | 5 // 堆的首元素具有最小的超时值 37 | 6 if ((ev = min_heap_top(&base->timeheap)) == NULL) { 38 | 7 // 如果没有定时事件,将等待时间设置为NULL,表示一直阻塞直到有I/O事件发生 39 | 8 *tv_p = NULL; 40 | 9 return (0); 41 | 10 } 42 | 11 // 取得当前时间 43 | 12 gettime(base, &now); 44 | 13 // 如果超时时间<=当前值,不能等待,需要立即返回 45 | 14 if (evutil_timercmp(&ev->ev_timeout, &now, <=)) { 46 | 15 evutil_timerclear(tv); 47 | 16 return (0); 48 | 17 } 49 | 18 // 计算等待的时间=当前时间-最小的超时时间 50 | 19 evutil_timersub(&ev->ev_timeout, &now, tv); 51 | 20 return (0); 52 | 21} 53 | ``` 54 | 55 | 56 | 57 | ### 2. Timer小根堆 58 | 59 | libevent使用堆来管理Timer事件,其key值就是事件的超时时间,源代码位于文件**min_heap.h**中。 60 | 所有的数据结构书中都有关于堆的详细介绍,向堆中插入、删除元素时间复杂度都是O(lgN),N为堆中元素的个数,而获取最小key值(小根堆)的复杂度为O(1)。堆是一个完全二叉树,基本存储方式是一个数组。 61 | libevent实现的堆还是比较轻巧的,虽然我不喜欢这种编码方式(搞一些复杂的表达式)。轻巧到什么地方呢,就以插入元素为例,来对比说明,下面伪代码中的size表示当前堆的元素个数: 62 | 63 | 典型的代码逻辑如下: 64 | 65 | ``` 66 | Heap[size++] = new; // 先放到数组末尾,元素个数+1 67 | // 下面就是shift_up()的代码逻辑,不断的将new向上调整 68 | _child = size; 69 | while(_child>0) // 循环 70 | { 71 | _parent = (_child-1)/2; // 计算parent 72 | if(Heap[_parent].key < Heap[_child].key) 73 | break; // 调整结束,跳出循环 74 | swap(_parent, _child); // 交换parent和child 75 | } 76 | ``` 77 | 78 | 而libevent的**heap**代码对这一过程做了优化,在插入新元素时,只是为新元素预留了一个位置**hole**(初始时hole位于数组尾部),但并不立刻将新元素插入到hole上,而是不断向上调整hole的值,将父节点向下调整,最后确认hole就是新元素的所在位置时,才会真正的将新元素插入到hole上,因此在调整过程中就比上面的代码少了一次赋值的操作,代码逻辑是: 79 | 80 | ``` 81 | // 下面就是shift_up()的代码逻辑,不断的将new的“预留位置”向上调整 82 | _hole = size; // _hole就是为new预留的位置,但并不立刻将new放上 83 | while(_hole>0) // 循环 84 | { 85 | _parent = (_hole-1)/2; // 计算parent 86 | if(Heap[_parent].key < new.key) 87 | break; // 调整结束,跳出循环 88 | Heap[_hole] = Heap[_parent]; // 将parent向下调整 89 | _hole = _parent; // 将_hole调整到_parent 90 | } 91 | Heap[_hole] = new; // 调整结束,将new插入到_hole指示的位置 92 | size++; // 元素个数+1 93 | ``` 94 | 95 | 由于每次调整都少做一次赋值操作,在调整路径比较长时,调整效率会比第一种有所提高。libevent中的**min_heap_shift_up_()**函数就是上面逻辑的具体实现,对应的向下调整函数是**min_heap_shift_down_()**。 96 | 97 | 举个例子,向一个小根堆3, 5, 8, 7, 12中插入新元素2,使用第一中典型的代码逻辑,其调整过程如下图所示: 98 | 99 | 100 | ![](../imgs/libevent9.webp) 101 | 102 | 使用libevent中的堆调整逻辑,调整过程如下图所示: 103 | 104 | 105 | ![](../imgs/libevent10.webp) 106 | 107 | 对于删除和元素修改操作,也遵从相同的逻辑,就不再罗嗦了。 108 | 109 | ### 3. 小节 110 | 111 | 通过设置系统I/O机制的wait时间,从而简洁的集成Timer事件;主要分析了libevent对堆调整操作的优化。 112 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析10.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析10 2 | 3 | **支持I/O多路复用技术** 4 | 5 | libevent的核心是事件驱动、同步非阻塞,为了达到这一目标,必须采用系统提供的I/O多路复用技术,而这些在Windows、Linux、Unix等不同平台上却各有不同,如何能提供优雅而统一的支持方式,是首要关键的问题,这其实不难,本节就来分析一下。 6 | 7 | ### 1. 统一的关键 8 | 9 | libevent支持多种I/O多路复用技术的关键就在于结构体**eventop**,这个结构体前面也曾提到过,它的成员是一系列的函数指针, 定义在**event-internal.h**文件中: 10 | 11 | ``` 12 | struct eventop { 13 | const char *name; 14 | void *(*init)(struct event_base *); // 初始化 15 | int (*add)(void *, struct event *); // 注册事件 16 | int (*del)(void *, struct event *); // 删除事件 17 | int (*dispatch)(struct event_base *, void *, struct timeval *); // 事件分发 18 | void (*dealloc)(struct event_base *, void *); // 注销,释放资源 19 | /* set if we need to reinitialize the event base */ 20 | int need_reinit; 21 | }; 22 | ``` 23 | 24 | 在libevent中,每种**I/O demultiplex**机制的实现都必须提供这五个函数接口,来完成自身的初始化、销毁释放;对事件的注册、注销和分发。 25 | 比如对于epoll,libevent实现了5个对应的接口函数,并在初始化时并将eventop的5个函数指针指向这5个函数,那么程序就可以使用epoll作为I/O demultiplex机制了。 26 | 27 | ### 2. 设置I/O demultiplex机制 28 | 29 | libevent把所有支持的I/O demultiplex机制存储在一个全局静态数组**eventops**中,并在初始化时选择使用何种机制,数组内容根据优先级顺序声明如下: 30 | 31 | ``` 32 | /* In order of preference */ 33 | static const struct eventop *eventops[] = { 34 | #ifdef HAVE_EVENT_PORTS 35 | &evportops, 36 | #endif 37 | #ifdef HAVE_WORKING_KQUEUE 38 | &kqops, 39 | #endif 40 | #ifdef HAVE_EPOLL 41 | &epollops, 42 | #endif 43 | #ifdef HAVE_DEVPOLL 44 | &devpollops, 45 | #endif 46 | #ifdef HAVE_POLL 47 | &pollops, 48 | #endif 49 | #ifdef HAVE_SELECT 50 | &selectops, 51 | #endif 52 | #ifdef WIN32 53 | &win32ops, 54 | #endif 55 | NULL 56 | }; 57 | ``` 58 | 59 | 然后libevent根据系统配置和编译选项决定使用哪一种I/O demultiplex机制,这段代码在函数**event_base_new()**中: 60 | 61 | ``` 62 | base->evbase = NULL; 63 | for (i = 0; eventops[i] && !base->evbase; i++) 64 | { 65 | base->evsel = eventops[i]; 66 | base->evbase = base->evsel->init(base); 67 | } 68 | 69 | base->evbase = NULL; 70 | for (i = 0; eventops[i] && !base->evbase; i++) 71 | { 72 | base->evsel = eventops[i]; 73 | base->evbase = base->evsel->init(base); 74 | } 75 | ``` 76 | 77 | 可以看出,libevent在编译阶段选择系统的I/O demultiplex机制,而不支持在运行阶段根据配置再次选择。 78 | 79 | 以Linux下面的epoll为例,实现在源文件**epoll.c**中,eventops对象epollops定义如下: 80 | 81 | ``` 82 | const struct eventop epollops = { 83 | "epoll", 84 | epoll_init, 85 | epoll_add, 86 | epoll_del, 87 | epoll_dispatch, 88 | epoll_dealloc, 89 | 1 /* need reinit */ 90 | }; 91 | ``` 92 | 93 | 变量epollops中的函数指针具体声明如下,注意到其返回值和参数都和eventop中的定义严格一致,这是函数指针的语法限制。 94 | 95 | ``` 96 | static void *epoll_init (struct event_base *); 97 | static int epoll_add (void *, struct event *); 98 | static int epoll_del (void *, struct event *); 99 | static int epoll_dispatch(struct event_base *, void *, struct timeval *); 100 | static void epoll_dealloc (struct event_base *, void *); 101 | ``` 102 | 103 | 那么如果选择的是epoll,那么调用结构体eventop的**init**和**dispatch**函数指针时,实际调用的函数就是epoll的初始化函数**epoll_init()**和事件分发函数**epoll_dispatch()**了; 104 | 105 | http://blog.csdn.net/sparkliang/archive/2009/06/09/4254115.aspx 106 | 同样的,上面epollops以及epoll的各种函数都直接定义在了**epoll.c**源文件中,对外都是不可见的。对于libevent的使用者而言,完全不会知道它们的存在,对epoll的使用也是通过eventop来完成的,达到了信息隐藏的目的。 107 | 108 | ### 3. 小节 109 | 110 | 支持多种I/O demultiplex机制的方法其实挺简单的,借助于函数指针就OK了。通过对源代码的分析也可以看出,libevent是在编译阶段选择系统的I/O demultiplex机制的,而不支持在运行阶段根据配置再次选择。 111 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析12.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析12 2 | 3 | **让libevent支持多线程** 4 | 5 | libevent本身不是多线程安全的,在多核的时代,如何能充分利用CPU的能力呢,这一节来说说如何在多线程环境中使用libevent,跟源代码并没有太大的关系,纯粹是使用上的技巧。 6 | 7 | ### 1. 错误使用示例 8 | 9 | 在多核的CPU上只使用一个线程始终是对不起CPU的处理能力啊,那好吧,那就多创建几个线程,比如下面的简单服务器场景。 10 | 1 主线程创建工作线程1; 11 | 2 接着主线程监听在端口上,等待新的连接; 12 | 3 在线程1中执行event事件循环,等待事件到来; 13 | 4 新连接到来,主线程调用libevent接口event_add将新连接注册到libevent上; 14 | … … 15 | 上面的逻辑看起来没什么错误,在很多服务器设计中都可能用到主线程和工作线程的模式…. 16 | 可是就在线程1注册事件时,主线程很可能也在操作事件,比如删除,修改,通过libevent的源代码也能看到,没有同步保护机制,问题麻烦了,看起来不能这样做啊,难道只能使用单线程不成!? 17 | 18 | ### 2. 支持多线程的几种模式 19 | 20 | libevent并不是线程安全的,但这不代表libevent不支持多线程模式,其实方法在前面已经将signal事件处理时就接触到了,那就是**消息通知机制**。 21 | 一句话,“你发消息通知我,然后再由我在合适的时间来处理”; 22 | 说到这就再多说几句,再打个比方,把你自己比作一个工作线程,而你的头是主线程,你有一个消息信箱来接收别人发给你的消息,当时头有个新任务要指派给你。 23 | 24 | #### 2.1 暴力抢占 25 | 26 | 那么第一节中使用的多线程方法相当下面的流程: 27 | 1 当时你正在做事,比如在写文档; 28 | 2 你的头找到了一个任务,要指派给你,比如帮他搞个PPT,哈; 29 | 3 头命令你马上搞PPT,你这是不得不停止手头的工作,把PPT搞定了再接着写文档; 30 | … 31 | 32 | #### 2.2 纯粹的消息通知机制 33 | 34 | 那么基于纯粹的消息通知机制的多线程方式就像下面这样: 35 | 1 当时你正在写文档; 36 | 2 你的头找到了一个任务,要指派给你,帮他搞个PPT; 37 | 3 头发个消息到你信箱,有个PPT要帮他搞定,这时你并不鸟他; 38 | 4 你写好文档,接着检查消息发现头有个PPT要你搞定,你开始搞PPT; 39 | … 40 | 第一种的好处是消息可以立即得到处理,但是很方法很粗暴,你必须立即处理这个消息,所以你必须处理好切换问题,省得把文档上的内容不小心写到PPT里。在操作系统的进程通信中,消息队列(消息信箱)都是操作系统维护的,你不必关心。 41 | 第二种的优点是通过消息通知,切换问题省心了,不过消息是不能立即处理的(基于消息通知机制,这个总是难免的),而且所有的内容都通过消息发送,比如PPT的格式、内容等等信息,这无疑增加了**通信开销**。 42 | 43 | #### 2.3 消息通知+同步层 44 | 45 | 有个折中机制可以减少消息通信的开销,就是提取一个同步层,还拿上面的例子来说,你把工作安排都存放在一个工作队列中,而且你能够保证“任何人把新任务扔到这个队列”,“自己取出当前第一个任务”等这些操作都能够保证不会把队列搞乱(其实就是个加锁的队列容器)。 46 | 再来看看处理过程和上面有什么不同: 47 | 1 当时你正在写文档; 48 | 2 你的头找到了一个任务,要指派给你,帮他搞个PPT; 49 | 2 头有个PPT要你搞定,他把任务push到你的工作队列中,包括了PPT的格式、内容等信息; 50 | 3 头发个消息(一个字节)到你信箱,有个PPT要帮他搞定,这时你并不鸟他; 51 | 4 你写好文档,发现有新消息(这预示着有新任务来了),检查工作队列知道头有个PPT要你搞定,你开始搞PPT; 52 | … 53 | 工作队列其实就是一个加锁的容器(队列、链表等等),这个很容易实现实现;而消息通知仅需要一个字节,具体的任务都push到了在工作队列中,因此想比2.2减少了不少通信开销。 54 | 多线程编程有很多陷阱,线程间资源的同步互斥不是一两句能说得清的,而且出现bug很难跟踪调试;这也有很多的经验和教训,因此如果让我选择,在绝大多数情况下都会选择机制3作为实现多线程的方法。 55 | 56 | ### 3. 例子——memcached 57 | 58 | **Memcached**中的网络部分就是基于libevent完成的,其中的多线程模型就是典型的**消息通知+同步层机制**。下面的图足够说明其多线程模型了,其中有详细的文字说明。 59 | 60 | ![](../imgs/libevent11.webp) 61 | 62 | 注:该图的具体出处忘记了,感谢原作者。 63 | 64 | ### 4. 小节 65 | 66 | 本节更是libevent的使用方面的技巧,讨论了一下如何让libevent支持多线程,以及几种支持多线程的机制,和memcached使用libevent的多线程模型。 67 | -------------------------------------------------------------------------------- /articles/libevent源码深度剖析/libevent源码深度剖析13.md: -------------------------------------------------------------------------------- 1 | # libevent源码深度剖析13 2 | 3 | **libevent信号处理注意点** 4 | 5 | 前面讲到了 libevent 实现多线程的方法,然而在多线程的环境中注册信号事件,还是有一些情况需要小心处理,那就是不能在多个 libevent 实例上注册信号事件。依然冠名追加到 libevent 系列。 6 | 7 | 8 | 9 | 以 2 个线程为例,做简单的场景分析。 10 | 11 | 1 首先是创建并初始化线程 1 的 libevent 实例 base1 ,线程 2 的 libevent 实例 base2 ; 12 | 13 | 2 在 base1 上注册 **SIGALRM** 信号;在 base2 上注册 **SIGINT** 信号; 14 | 15 | 3 假设当前 base1 和 base2 上都没有注册其他的事件; 16 | 17 | 4 线程 1 和 2 都进入 **event_base_loop** 事件循环: 18 | 19 | ![](../imgs/libevent12.webp) 20 | 21 | 5 假设线程 1 先进入 **event_base_loop** ,并设置 **evsignal_base = base1** ;并等待; 22 | 23 | 6 接着线程 2 也进入 **event_base_loop** ,并设置 **evsignal_base = base2** ;并等待; 24 | 25 | 于是 **evsignal_base** 就指向了 base2 ; 26 | 27 | 7 信号 **ALARM** 触发,调用服务例程: 28 | 29 | ``` 30 | static void evsignal_handler(int sig){ 31 | ... 32 | evsignal_base->sig.evsigcaught[sig]++; 33 | evsignal_base->sig.evsignal_caught = 1; 34 | /* Wake up our notification mechanism */ 35 | send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); 36 | ... 37 | } 38 | ``` 39 | 40 | 于是 base2 得到通知 ALARM 信号发生了,而实际上 ALARM 是注册在 base1 上的, base2 上的 ALARM 注册 event 是空的,于是处理函数将不能得到调用;因此在 libevent 中,如果需要处理信号,只能将信号注册到一个 libevent 实例上。 41 | 42 | memcached 就没有使用 libevent 提供的 signal 接口,而是直接使用系统提供的原生 API ,看起来这样更简洁。 43 | 44 | 45 | 46 | libevent源码深度剖析全系列完。 47 | -------------------------------------------------------------------------------- /articles/wechat_pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/wechat_pay.png -------------------------------------------------------------------------------- /articles/zfb_pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/zfb_pay.png -------------------------------------------------------------------------------- /articles/作者的故事/README.md: -------------------------------------------------------------------------------- 1 | ## 作者的故事 2 | 3 | * [我的 2019](我的2019.md) 4 | 5 | * [我是如何年薪五十万的](我是如何年薪五十万的.md) 6 | 7 | -------------------------------------------------------------------------------- /articles/后端开发相关的书籍/README.md: -------------------------------------------------------------------------------- 1 | ## 后端开发相关的书籍 2 | 3 | * [后台开发应该读的书](后台开发应该读的书.md) 4 | 5 | -------------------------------------------------------------------------------- /articles/多线程/README.md: -------------------------------------------------------------------------------- 1 | ## 多线程 2 | 3 | * [后台C++开发你一定要知道的条件变量](后台C++开发你一定要知道的条件变量.md) 4 | 5 | * [整型变量赋值是原子操作吗?](整型变量赋值是原子操作吗?.md) 6 | 7 | -------------------------------------------------------------------------------- /articles/多线程/整型变量赋值是原子操作吗?.md: -------------------------------------------------------------------------------- 1 | # 整型变量赋值是原子操作吗? 2 | 3 | ## 整型变量赋值操作不是原子操作 4 | 5 | 那么为什么整型变量的操作不是原子性的呢?常见的整型变量操作有如下几种情况: 6 | 7 | 给整型变量赋值一个确定的值,如 8 | 9 | ``` 10 | int a = 1; 11 | ``` 12 | 13 | 这条指令操作一般是原子的,因为对应着一条计算机指令,cpu将立即数1搬运到变量**a**的内存地址中即可,汇编指令如下: 14 | 15 | ``` 16 | mov dword ptr [a], 2 17 | ``` 18 | 19 | 然后这确是最不常见的情形,由于现代编译器一般有优化策略,如果变量**a**的值在编译期间就可以计算出来(例如这里的例子中**a**的值就是**1**),那么**a**这个变量本身在正式版本的软件中(release版)就很有可能被编译器优化掉,使用**a**的地方,直接使用常量**1**来代替。所以实际的执行指令中,这样的指令存在的可能性比较低。 20 | 21 | 变量自身增加或者减去一个值,如 22 | 23 | ``` 24 | a ++; 25 | ``` 26 | 27 | 从C/C++语法的级别来看,这是一条语句,是原子的;但是从实际执行的二进制指令来看,也不是原子的,其一般对应三条指令,首先将变量**a**对应的内存值搬运到某个寄存器(如**eax**)中,然后将该寄存器中的值自增**1**,再将该寄存器中的值搬运回**a**的内存中: 28 | 29 | ``` 30 | mov eax, dword ptr [a] 31 | inc eax 32 | mov dword ptr [a], eax 33 | ``` 34 | 35 | 现在假设**a**的值是0,有两个线程,每个线程对变量**a**的值递增**1**,我们预想的结果应该是**2**,可实际运行的结果可能是**1**!是不是很奇怪?分析如下: 36 | 37 | ``` 38 | int a = 0; 39 | 40 | //线程1 41 | void thread_func1() 42 | { 43 | a ++; 44 | } 45 | 46 | //线程2 47 | void thread_func2() 48 | { 49 | a ++; 50 | } 51 | ``` 52 | 53 | ![](../imgs/atomic1.webp) 54 | 55 | 我们预想的结果是**线程1**和**线程2**的三条指令各自执行,最终**a**的值为**2**,但是由于操作系统线程调度的不确定性,**线程1**执行完指令①和②后,**eax**寄存器中的值为**1**,此时操作系统切换到**线程2**执行,执行指令③④⑤,此时**eax**的值变为**1**;接着操作系统切回**线程1**继续执行,执行指令⑦,得到**a**的最终结果**1**。 56 | 57 | - 把一个变量的值赋值给另外一个变量,或者把一个表达式的值赋值给另外一个变量,如 58 | 59 | ``` 60 | int a = b; 61 | ``` 62 | 63 | 从C/C++语法的级别来看,这是也是一条语句,是原子的;但是从实际执行的二进制指令来看,由于现代计算机CPU架构体系的限制,数据不可以直接从内存搬运到另外一块内存,必须借助寄存器中断,这条语句一般对应两条计算机指令,即将变量**b**的值搬运到某个寄存器(如**eax**)中,再从该寄存器搬运到变量**a**的内存地址: 64 | 65 | ``` 66 | mov eax, dword ptr [b] 67 | mov dword ptr [a], eax 68 | ``` 69 | 70 | 既然是两条指令,那么多个线程在执行这两条指令时,某个线程可能会在第一条指令执行完毕后被剥夺CPU时间片,切换到另外一个线程而产生不确定的情况。这和上一种情况类似,就不再详细分析了。 71 | 72 | 说点题外话,网上很多人强调某些特殊的整型数值类型(如bool类型)的操作是原子的,这是由于,某些CPU生产商开始有意识地从硬件平台保证这一类操作的原子性,但这并不是每一种类型的CPU架构都支持,在这一事实成为标准之前,我们在多线程操作整型时还是老老实实使用下文介绍的原子操作或线程同步技术来对这些数据类型进行保护。 73 | -------------------------------------------------------------------------------- /articles/服务器开发案例实战/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/服务器开发案例实战/.DS_Store -------------------------------------------------------------------------------- /articles/服务器开发案例实战/1从一款多人联机实时对战游戏开始.md: -------------------------------------------------------------------------------- 1 | ## 从零学习开源项目系列(一) 从一款多人联机实时对战游戏开始 2 | 3 | **写在前面的话** 4 | 5 | 经常有学生或者初学者问我如何去阅读和学习一个开源软件的代码,也有不少朋友在工作岗位时面对前同事留下的项目,由于文档不完善、代码注释少、工程数量大,而无从下手。本文将来通过一个多人联机实时对战游戏——最后一战,来解答以上问题。 6 | 7 | 其实,我以上问题在我是一个学生时,我也同样因此而困惑,但是后来,我发现,对于文档缺失、注释缺失的项目,需要自己摸索,虽然是挑战,同时也是机遇——一个不错的学习机会。因为至少有代码,正如侯捷大师所说的的,**“源码面前,了无秘密”**,所以我们应该**“read the fucking code”**。 8 | 9 | 所以,这个系列的文章,我们分析“最后一战”这个游戏源码时,我们不会按照传统的思路:先介绍总结的程序结构,再介绍各个模块的细节,因为,当我们面对一套陌生的源码时,尤其是在文档缺失的情况下,我们根本无法开始就掌握这个项目的总体结构,我们只能从零开始一个个模块的对代码进行阅读和调试,所以我们这个系列的文章也按这个思路来分析,以真实的案例来教会新手一步步读懂一个开源项目的代码。 10 | 11 | 我们先来看下这个游戏的内容吧,下面给出游戏画面的部分截图: 12 | 13 | ![](../imgs/zhyz1.webp) 14 | 15 | ![](../imgs/zhyz2.webp) 16 | 17 | ![](../imgs/zhyz3.webp) 18 | 19 | ![](../imgs/zhyz4.webp) 20 | 21 | ![](../imgs/zhyz5.webp) 22 | 23 | ![](../imgs/zhyz6.webp) 24 | 25 | 这是一款类似于王者荣耀、dota之类的5v5实时RPG竞技游戏。 26 | 27 | 客户端的逻辑比较简单,主要是一些游戏特效和动画(基于Unity 3D),所以这里我们主要分析游戏的服务器端源码。 28 | 29 | 先介绍一下推荐的源码的运行和开发环境(我的配置): 30 | 31 | **Windows 7** 32 | 33 | **Visual Studio 2010** 34 | 35 | 服务器端有非常多的模块,这里先截一张主要模块的项目图示: 36 | 37 | ![](../imgs/zhyz7.webp) 38 | 39 | 从下一篇文章开始,我们将介绍如何学习这样的源码。 40 | 41 | 欢迎阅读下一篇**《从零学习开源项目系列(二) 最后一战概况》**。 42 | 43 | > 源码下载方法: 44 | > 45 | > 微信搜索公众号**『高性能服务器开发』**(中文名:高性能服务器开发),关注公众号后,在公众号中回复**『英雄联盟』**,即可得到下载链接。(喷子和代码贩子请远离!) -------------------------------------------------------------------------------- /articles/服务器开发案例实战/README.md: -------------------------------------------------------------------------------- 1 | ## 服务器开发案例实战 2 | 3 | * [从零实现一个http服务器](从零实现一个http服务器.md) 4 | 5 | * [从零实现一款12306刷票软件](从零实现一款12306刷票软件.md) 6 | 7 | * [从零实现一个邮件收发客户端](从零实现一个邮件收发客户端.md) 8 | 9 | * [从零开发一个WebSocket服务器](从零开发一个WebSocket服务器.md) 10 | 11 | * [从零学习开源项目系列(一) 从一款多人联机实时对战游戏开始](1从一款多人联机实时对战游戏开始.md) 12 | 13 | * [从零学习开源项目系列(二) 最后一战概况](2最后一战概况.md) 14 | 15 | * [从零学习开源项目系列(三) CSBattleMgr服务源码研究](3CSBattleMgr服务源码研究.md) 16 | 17 | * [从零学习开源项目系列(四)LogServer源码探究](4LogServer源码探究.md) 18 | 19 | -------------------------------------------------------------------------------- /articles/游戏开发专题/2网络游戏服务器开发框架设计介绍.md: -------------------------------------------------------------------------------- 1 | # 2 网络游戏服务器开发框架设计介绍 2 | 3 | 在开发过程中,会先有一份开发大纲或是一份策划案,但是这些在我的开发中可能不会有,或者即使有,也很有可能是我随性写下来的,但是我会尽可能写好它。 4 | 5 | **网络通信层,我会放到单独的SOCKET编程中去讲解,这里的主题是游戏的架构设计以及系统模块间的协同工作。** 6 | 7 | 所以,在这里假设所有的网络层都已经开发完毕,具体的网络层开发代码不会再这里出现,因为这需要很多年的开发经验,或者对SOCKET有一定的了解才能够讲述清楚或理解,所以我不想再我还没有足够的把握之前去说这样的问题,主要问题是不想让人说我不专业;另一方面是不希望给没有接触过SOCKET编程或了解不多的人带来误导或困扰。 8 | 9 | 在开发游戏具体功能前,**第一个要做的就是理清系统功能**,这里的系统功能并不是具体的游戏功能,而是从软件角度出发的,行业内部称其为分布式服务器开发,讲的是如何构建一个可移植、可分布到不同网络机器独立或依赖运行的应用程序。 10 | 11 | 本系列开发教程是我个人游戏经历和工作历程的一个沉淀,也是我个人主观的一个未实现版本,在这里,我希望它可以以教程的方式存在,并去按部就班的一步一步实现出来。所有的源码代码都是开源的,我不会有丝毫保留,这样做的目的是方便很多像我一样的游戏狂热者入门无门,另一方面也是希望前辈们可以对我的错误进行指正。下面将具体描述服务器的划分以及功能实现。 12 | 13 | 此系列开发教程,总共将分为10个模块:它们分别为 14 | 15 | - LoginGate服务器、 16 | - LoginServer服务器、 17 | - GameGate服务器、 18 | - GameServer服务器、 19 | - IMServer服务器、 20 | - AIServer服务器、 21 | - CenterServer服务器、 22 | - BillingServer服务器、 23 | - WebServices服务器、 24 | - DBServer服务器。 25 | 26 | 1 27 | 28 | 29 | 30 | **LoginGate**:登陆网关服务器,将所有的LoginServer服务器地址暴露给最终用户,每个LoginGate服务可以挂接n个LoginServer,将最终用户的所有请求转发给目标LoginServer。当最终用户通过此服务完成登陆后,会与该服务断开连接,断开连接前,服务器会将数据上报给GameGate服务。 31 | 32 | 2 33 | 34 | **LoginServer**:登陆服务器,仅作于内部服务与LoginGate进行连接,所有的最终用户请求由LoginGate过滤后,转发过来进行处理。与LoginGate的所有通信都是明文,即未加密数据。 35 | 36 | 3 37 | 38 | **GameGate:**游戏网关服务器,与LoginGate协作完成最终用户的登陆过程,每一个服务会连接到唯一一个LoginGate服务上进行注册,LoginGate会将以完成验证登陆的用户信息同步到所有已注册成功的GameGate上,根据注册不同的GameGate类型信息,LoginGate会发生不同的通过认证的最终用户信息。 39 | 40 | GameGate挂接n个GameServer服务到自身,此服务将所有注册到自身的GameServer信息发送给最终用户,提供用户选择具体的区或线路进行游戏(区和线路在不同的游戏设定中有不同的定义),在这里区的定义对应的是GameGate,每一个GameGate可以表示物理或逻辑上的多个游戏分区,每个分区由至少一个GameServer组成; 41 | 42 | 线路定义为GameServer,每一个GameServer代表一条线路,线路之间互相不可见,但是可以通过IMServer进行一些扩展通信,例如公会、好友、聊天等服务可以设置透明通信或隐藏通信。透明通信由IMServer向目标GameServer转发请求,并进行处理;隐藏通信仅在当前GameServer进行处理,不会做跨越性操作。 43 | 44 | 4 45 | 46 | **GameServer**:游戏服务器,作为内部服务与GameGate协作处理最终用户的请求,这个服务主要处理游戏逻辑,例如战斗。此服务启动后,会根据配置文件的配置信息进行相应的服务注册,该服务启动成功后,会注册到GameGate和IMServer、AIServer服务器,它们分别提供最终用户游戏、交友、公会、聊天和智能体的移动、创建、销毁等服务。**作为整个游戏的核心处理服务器**,会处理掉大部分的用户交互服务请求,只有在不能处理的情况下,才会请求其它服务协同处理。 47 | 48 | 5 49 | 50 | **IMServer**:IM通信服务器,全称InstantMessaging(译为即时通讯),ICQ、MSN、QQ等聊天工具都属于此范畴。此服务的作用是提供物理或逻辑不同位置的GameServer上的最终用户通讯的一个媒介,用户成功登陆GameServer时,会将自己的好友、公会信息注册到此服务上,当需要跨GameServer服务时,共IMServer使用。此服务主要提供聊天、交友、交易、公会等社交类行为服务,该服务可以直接或间接的与最终用户进行通信,但最终用户无法直接与该服务进行通信,比如请求操作,所有的用户操作都由GameServer转发,IMServer可以选择性的直接反馈最终用户或通过GameServer反馈。 51 | 52 | 6 53 | 54 | **AIServer:**人工智能服务器,全称Artificial Intelligence(译为人工智能),例如现代服务性机器人(自动吸尘器、智能探测仪、智能防爆装置等)都属于人工智能范畴。这里的人工智能主要体现在游戏中的NPC、MONSTER等有行为表现物体。GameServer启动后会连接到此服务进行注册,并获取所需智能体的信息,以反馈给最终用户,并最终显示在用户应用程序中。该服务主要控制智能体的移动、攻击、创建、销毁等行为,另外包括在战斗中或非战斗状态下的行为,比如游走在街道上的商品小贩;在搜索到攻击目标时,主动或召集附近的战斗单位一起攻击用户,都属于该服务的工作内容。 55 | 56 | 7 57 | 58 | **CenterServer:**中心服务器,用于监控、更新已注册到此服务的状态,比如电信1区(傲视天地)服务器的运行状态等。此服务主要是管理除自身以外的所有服务程序的运行状态,以及时反馈给技术活运维人员。 59 | 60 | 8 61 | 62 | **BillingServer:**计费服务器,用于计算用户在游戏中的消耗、增值;比如XX在游戏中购买了一个双倍经验卡,消耗10金币,或者用户通过网站形式进行充值,都会通过该服务反馈给用户最终结果。 63 | 64 | 9 65 | 66 | **WebServices:**网站服务,主要用于网站与游戏之间的交互。比如XX用户通过网站进行充值服务,充值成功后,通知计费服务以响应用户操作;或通过网站进行游戏激活、礼品领取等,都需要此服务与游戏应用程序进行交互,以体现实时的变化。 67 | 68 | 10 69 | 70 | DBServer:用于全局数据维护,例如更新、查询、插入、删除操作;这些数据包含用户账号、充值、代金卷、点卡、月卡以及游戏中需要用到的角色数据。 71 | 72 | 服务器整体架构图分布示意图: 73 | 74 | ![](../imgs/game1.webp) 75 | 76 | 77 | 78 | LoginGate内部运行示意图: 79 | 80 | ![](../imgs/game2.webp) 81 | 82 | 83 | 84 | LoginServer内部运行示意图: 85 | 86 | ![](../imgs/game3.webp) 87 | 88 | 89 | 90 | 由于其它服务器模块程序的内部图与这两个类似,所以就不在这个上面耽搁太多时间,下一篇将讲述具体的游戏开发,网络库使用的是开源库ACE,下载地址http://download.dre.vanderbilt.edu/previous_versions/ACE-5.8.0.zip。 91 | -------------------------------------------------------------------------------- /articles/游戏开发专题/3游戏后端开发需要掌握的知识.md: -------------------------------------------------------------------------------- 1 | # 3 游戏后端开发需要掌握的知识 2 | 3 | 这篇是从网上找到牛人的**博客总结**下来的: 4 | 5 | ![](../imgs/game4.webp) 6 | 7 | **实战方面:** 8 | 9 | (1)两种在知名IT公司使用的游戏服务器架构设计 10 | 11 | **点击图片可以放大** 12 | 13 | ![](../imgs/game5.webp) 14 | 15 | 16 | 17 | 1 18 | 19 | **各个服务器的功能以及作用:** 20 | 21 | - **CenterServer服务器管理器:**管理所有的服务器,分配服务器的端口,负责全局的逻辑(管理),对各功能服务器和场景服务器提供服务,保证服务器的合法性 22 | - **DBserver**角色档案缓冲服务器 23 | - **GameServer**逻辑服务器:玩家的实时同步在里面实现 24 | - **GateServer**网关服务器:负责消息转发 25 | - **LoginServer登录服务器:**连接账号数据 26 | 27 | 2 28 | 29 | **不带负载均衡的和带负载均衡:** 30 | 31 | **相同点:** 32 | 33 | ​ 与带负载均衡大概的架构相同 34 | 35 | **不同点:** 36 | 37 | - 不带负载均衡 38 | 39 | Gate Server 和Game Server之间是**一对一**的关系,每个Game Server能容纳的玩家数量是一定的,正常情况下一个Gate Server的对应一个Game Server实时在线人数能达到3000人,一旦达到峰值,就会找下一个对应的Game Server。 40 | 41 | 各个**Gate Server服务器之间是不通信**的 42 | 43 | 44 | 45 | 46 | 47 | - 带负载均衡 48 | 49 | 一个Gate Server的**对应多个**Game Server 50 | 51 | **各个GateServer之间可以互相通信**,而且还可以随意扩展,通过配置文件可以实现配置 52 | 53 | 54 | 55 | 3 56 | 57 | **服务器的工作过程:** 58 | 59 | 1. 用户从客户端**选择**游戏服务器列表 60 | 2. **登录**到Login Server,在登陆的过程中 61 | 3. 先去平台服务器进行账号的**验证** 62 | 4. 验证通过后会通知Login Server,然后Login Server会把验证的消息发送 到center Server,**请求**其中的Gate Server的地址和端口 63 | 5. Center Server会找一个可用的Gate Server信息,**发送回**LoginServer 64 | 6. Login Server会把**消息发送**给客户端 65 | 7. 客户端**断开**与Login Server的连接,然后与Game Server 连接进入游戏场景中 -------------------------------------------------------------------------------- /articles/游戏开发专题/7QQ游戏百万人同时在线服务器架构实现.md: -------------------------------------------------------------------------------- 1 | # 7 QQ游戏百万人同时在线服务器架构实现 2 | 3 | QQ游戏于前几日终于突破了百万人同时在线的关口,向着更为远大的目标迈进,这让其它众多传统的棋牌休闲游戏平台黯然失色,相比之下,联众似乎已经根本不是QQ的对手,因为QQ除了这100万的游戏在线人数外,它还拥有3亿多的注册量(当然很多是重复注册的)以及QQ聊天软件900万的同时在线率,我们已经可以预见未来由QQ构建起来的强大棋牌休闲游戏帝国。 4 | 5 | 服务器程序,其可承受的同时连接数目是有理论峰值的,在实际应用中,能达到一万人的同时连接并能保证正常的数据交换已经是很不容易了,通常这个值都在2000到5000之间,据说QQ的单台服务器同时连接数目也就是在这个值这间。 6 | 7 | **如果要实现2000到5000用户的单服务器同时在线**,是不难的。在windows下,**比较成熟的技术是采用IOCP---完成端口**。只要运用得当,一个完成端口服务器是完全可以达到2K到5K的同时在线量的。但,5K这样的数值离百万这样的数值实在相差太大了,所以,**百万人的同时在线是单台服务器肯定无法实现的。** 8 | 9 | 要实现百万人同时在线,**首先**要实现一个比较完善的完成端口服务器模型,这个模型要求至少可以承载2K到5K的同时在线率(当然,如果你MONEY多,你也可以只开发出最多允许100人在线的服务器)。在构**建好了基本的完成端口服务器之后**,就是有关服务器组的架构设计了。之所以说这是一个**服务器组**,是因为它绝不仅仅只是一台服务器,也绝不仅仅是只有一种类型的服务器。 10 | 11 | 简单地说,**实现百万人同时在线的服务器模型应该是:登陆服务器+大厅服务器+房间服务器**。当然,也可以是其它的模型,但其基本的思想是一样的。下面,我将逐一介绍这三类服务器的各自作用。 12 | 13 | **/ 1 /** 14 | 15 | **登陆服务器:**一般情况下,我们会向玩家开放若干个公开的登陆服务器,就如QQ登陆时让你选择的从哪个QQ游戏服务器登陆一样,QQ登陆时让玩家选择的六个服务器入口实际上就是登陆服务器。**登陆服务器主要完成负载平衡的作用**。详细点说就是,在登陆服务器的背后,有N个大厅服务器,登陆服务器只是用于为当前的客户端连接选择其下一步应该连接到哪个大厅服务器,当登陆服务器为当前的客户端连接选择了一个合适的大厅服务器后,客户端开始根据登陆服务器提供的信息连接到相应的大厅上去,同时客户端断开与登陆服务器的连接,为其他玩家客户端连接登陆服务器腾出套接字资源。 16 | 17 | 在**设计登陆服务器**时,至少应该有以下**功能**:N个大厅服务器的每一个大厅服务器都要与所有的登陆服务器保持连接,并实时地把本大厅服务器当前的同时在线人数通知给各个登陆服务器,这其中**包括**:用户进入时的同时在线人数增加信息以及用户退出时的同时在线人数减少信息。这里的各个大厅服务器同时在线人数信息就是登陆服务器为客户端选择某个大厅让其登陆的依据。**举例**来说,玩家A通过登陆服务器1连接到登陆服务器,登陆服务器开始为当前玩家在众多的大厅服务器中根据哪一个大厅服务器人数比较少来选择一个大厅,同时把这个大厅的连接IP和端口发给客户端,客户端收到这个IP和端口信息后,根据这个信息连接到此大厅,同时,客户端断开与登陆服务器之间的连接,这便是用户登陆过程中,在登陆服务器这一块的处理流程。 18 | 19 | **/ 2 /** 20 | 21 | **大厅服务器**:是普通玩家看不到的服务器,**它的连接IP和端口信息是登陆服务器通知给客户端的**。也就是说,在QQ游戏的本地文件中,具体的大厅服务器连接IP和端口信息是没有保存的。**大厅服务器的主要作用**是向玩家发送游戏房间列表信息。 22 | 23 | 这些**信息**包括: 24 | 25 | - 每个游戏房间的类型 26 | - 名称 27 | - 在线人数 28 | - 连接地址以及其它如游戏帮助文件URL的信息 29 | 30 | **从****界面上看的话**,大厅服务器就是我们输入用户名和密码并校验通过后进入的游戏房间列表界面。 31 | 32 | 大厅服务器,主要有以下**功能**: 33 | 34 | 1. 一是向当前玩家广播各个游戏房间在线人数信息; 35 | 2. 二是提供游戏的版本以及下载地址信息; 36 | 3. 三是提供各个游戏房间服务器的连接IP和端口信息; 37 | 4. 四是提供游戏帮助的URL信息; 38 | 5. 五是提供其它游戏辅助功能。 39 | 40 | 但在这众多的功能中,有一点是**最为核心**的,即:**为玩家提供进入具体的游戏房间的通道,让玩家顺利进入其欲进入的游戏房间。**玩家根据各个游戏房间在线人数,判定自己进入哪一个房间,然后双击服务器列表中的某个游戏房间后玩家开始进入游戏房间服务器。 41 | 42 | **/ 3 /** 43 | 44 | **游戏房间服务器**:具体地说就是如“斗地主1”,“斗地主2”这样的游戏房间。游戏房间服务器才是具体的负责执行游戏相关逻辑的服务器。这样的**游戏逻辑分为两大类**: 45 | 46 | - 第一类是**通用的游戏房间逻辑**,如:进入房间,离开房间,进入桌子,离开桌子以及在房间内说话等; 47 | - 第二类是**游戏桌子逻辑**,这个就是各种不同类型游戏的主要区别之处了,比如斗地主中的叫地主或不叫地主的逻辑等,当然,游戏桌子逻辑里也包括有通用的各个游戏里都存在的游戏逻辑,比如在桌子内说话等。 48 | 49 | **总之,游戏房间服务器才是真正负责执行游戏具体逻辑的服务器。** 50 | 51 | 这里提到的**三类服务器,均采用的是完成端口模型**,每个服务器最多连接数目是5000人,但是,我在游戏房间服务器上作了逻辑层的限定,最多只允许300人同时在线。其他两个服务器仍然允许最多5000人的同时在线。 52 | 53 | 如果按照这样的结构来设计,那么**要实现百万人的同时在线就应该是这样:** 54 | 55 | - 首先是大厅,1000000/5000=200。也就是说,至少要200台大厅服务器,但通常情况下,考虑到实际使用时服务器的处理能力和负载情况,应该至少准备250台左右的大厅服务器程序。 56 | - 另外,**具体的各种类型的游戏房间服务器需要多少,**就要根据当前玩各种类型游戏的玩家数目分别计算了,比如斗地主最多是十万人同时在线,每台服务器最多允许300人同时在线,那么需要的斗地主服务器数目就应该不少于:100000/300=333,准备得充分一点,就要准备350台斗地主服务器。 57 | - **除正常的玩家连接外,还要考虑到**:对于登陆服务器,会有250台大厅服务器连接到每个登陆服务器上,这是始终都要保持的连接; 58 | 59 | 而对于大厅服务器而言,如果仅仅有斗地主这一类的服务器,就要有350多个连接与各个大厅服务器始终保持着。所以从这一点看,结构在某些方面还存在着需要改进的地方,但**核心思想是:尽快地提供用户登陆的速度,尽可能方便地让玩家进入游戏中。** -------------------------------------------------------------------------------- /articles/游戏开发专题/README.md: -------------------------------------------------------------------------------- 1 | ## 游戏开发专题 2 | 3 | * [1 游戏服务器开发的基本体系与服务器端开发的一些建议](1游戏服务器开发的基本体系与服务器端开发的一些建议.md) 4 | 5 | * [2 网络游戏服务器开发框架设计介绍](2网络游戏服务器开发框架设计介绍.md) 6 | 7 | * [3 游戏后端开发需要掌握的知识](3游戏后端开发需要掌握的知识.md) 8 | 9 | * [4 关于游戏服务端架构的整理](4关于游戏服务端架构的整理.md) 10 | 11 | * [5 各类游戏对应的服务端架构](5各类游戏对应的服务端架构.md) 12 | 13 | * [6 从腾讯QQgame高性能服务器集群架构看“分而治之”与“自治”等分布式架构设计原则](6从腾讯QQgame高性能服务器集群架构看“分而治之”与“自治”等分布式架构设计原则.md) 14 | 15 | * [7 QQ游戏百万人同时在线服务器架构实现](7QQ游戏百万人同时在线服务器架构实现.md) 16 | 17 | * [8 大型多人在线游戏服务器架构设计](8大型多人在线游戏服务器架构设计.md) 18 | 19 | * [9 百万用户级游戏服务器架构设计](9百万用户级游戏服务器架构设计.md) 20 | 21 | * [10 十万在线的WebGame的数据库设计思路](10十万在线的WebGame的数据库设计思路.md) 22 | 23 | * [11 一种高性能网络游戏服务器架构设计](11一种高性能网络游戏服务器架构设计.md) 24 | 25 | * [12 经典游戏服务器端架构概述](12经典游戏服务器端架构概述.md) 26 | 27 | * [13 游戏跨服架构进化之路](13游戏跨服架构进化之路.md) 28 | 29 | -------------------------------------------------------------------------------- /articles/程序员必知必会的网络命令/Linux网络故障排查的瑞士军刀.md: -------------------------------------------------------------------------------- 1 | ## Linux 网络故障排查的瑞士军刀 2 | 3 | **nc** 即 **n**et**c**at 命令,这个工具在排查网络故障时非常有用,功能非常强大,因而被业绩称为网络界的“瑞士军刀”,请读者务必掌握。默认系统是没有这个命令的,你需要安装一下,安装方法: 4 | 5 | ``` 6 | yum install nc 7 | ``` 8 | 9 | **nc** 命令常见的用法是模拟一个服务器程序被其他客户端连接,或者模拟一个客户端连接其他服务器,连接之后就可以进行数据收发。我们来逐一介绍一下: 10 | 11 | - **模拟一个服务器程序** 12 | 13 | 使用 **-l** 选项(单词 **l**isten 的第一个字母)在某个 ip 地址和端口号上开启一个侦听服务,以便让其他客户端连接。通常为了显示更详细的信息,会带上 **-v** 选项。 14 | 15 | 示例如下: 16 | 17 | ``` 18 | [root@iZ238vnojlyZ ~]# nc -v -l 127.0.0.1 6000 19 | Ncat: Version 6.40 ( http://nmap.org/ncat ) 20 | Ncat: Listening on 127.0.0.1:6000 21 | ``` 22 | 23 | 这样就在 **6000** 端口开启了一个侦听服务器,我们可以通过 **127.0.0.1:6000** 去连接上去;如果你的机器可以被外网访问,你可以使用 **0.0.0.0** 这样的侦听地址,示例: 24 | 25 | ``` 26 | [root@iZ238vnojlyZ ~]# nc -v -l 0.0.0.0 6000 27 | Ncat: Version 6.40 ( http://nmap.org/ncat ) 28 | Ncat: Listening on 0.0.0.0:6000 29 | ``` 30 | 31 | - 模拟一个客户端程序 32 | 33 | 用 **nc** 命令模拟一个客户端程序时,我们不需要使用 **-l** 选项,直接写上 ip 地址(或域名,**nc** 命令可以自动解析域名)和端口号即可,示例如下: 34 | 35 | ``` 36 | ## 连接百度 web 服务器 37 | [root@iZ238vnojlyZ ~]# nc -v www.baidu.com 80 38 | Ncat: Version 6.40 ( http://nmap.org/ncat ) 39 | Ncat: Connected to 115.239.211.112:80. 40 | ``` 41 | 42 | 输出提示我们成功连接上百度 Web 服务器。 43 | 44 | 我们知道客户端连接服务器一般都是操作系统随机分配一个可用的端口号连接到服务器上去,使用 **nc** 命令作为客户端时可以使用 **-p** 选项指定使用哪个端口号连接服务器,例如,我们希望通过本地 5555 端口连接百度的 Web 服务器,可以这么输入: 45 | 46 | ``` 47 | [root@iZ238vnojlyZ ~]# nc -v -p 5555 www.baidu.com 80 48 | Ncat: Version 6.40 ( http://nmap.org/ncat ) 49 | Ncat: Connected to 115.239.211.112:80. 50 | ``` 51 | 52 | 再开一个 shell 窗口,我们使用上文中介绍的 **lsof** 命令验证一下,是否确实通过 **5555** 端口连接上了百度 Web 服务器。 53 | 54 | ``` 55 | [root@iZ238vnojlyZ ~]# lsof -Pni | grep nc 56 | nc 32610 root 3u IPv4 113369437 0t0 TCP 120.55.94.78:5555->115.239.211.112:80 (ESTABLISHED) 57 | ``` 58 | 59 | 结果确实如我们所期望的。 60 | 61 | 当然,当使用 **nc** 命令与对端建立连接后,我们可以发送消息。下面通过一个具体的例子来演示一下这个过程 62 | 63 | 1. 使用 **nc -v -l 0.0.0.0 6000** 模拟一个侦听服务,再新建一个 shell 窗口利用 **nc -v 127.0.0.1 6000** 模拟一个客户端程序连接刚才的服务器。 64 | 2. 此时在客户端和服务器就可以相互发消息了。我们可以达到一个简化版的 IM 软件聊天效果: 65 | 66 | **客户端效果:** 67 | 68 | ![](../imgs/nc1.png) 69 | 70 | **服务器端效果:** 71 | 72 | ![](../imgs/nc2.jpeg) 73 | 74 | 75 | 76 | 77 | 78 | > 果你在使用 nc 命令发消息时不小心输入错误,可以使用 **Ctrl + Backspace** 键删除。 79 | 80 | **nc** 命令默认会将 **\n** 作为每条消息的结束标志,如果你指定了 **-C** 选项,将会使用 **\r\n** 作为消息结束标志。 81 | 82 | **nc** 命令不仅可以发消息,同时也能发文件。我们也来演示一下: 83 | 84 | 需要注意的是是**接收文件的一方是服务器端,发送文件的一方是客户端**。 85 | 86 | 1. 服务器端命令: 87 | 88 | ``` 89 | nc -l ip地址 端口号 > 接收的文件名 90 | ``` 91 | 92 | 2. 客户端命令: 93 | 94 | ``` 95 | nc ip地址 端口号 < 发送的文件名 96 | ``` 97 | 98 | **服务器端效果**: 99 | 100 | ![img](../imgs/nc3.jpeg) 101 | 102 | **客户端效果:** 103 | 104 | ![img](https://mmbiz.qpic.cn/mmbiz_png/ic8RqseyjxMM4O9PrQeYEZ96kC0aP9fXq02fwwzmOXVibyIyH5Qa4Sc7BMZrOBjibg4wibnWmdFalicBMXpNicR3MOjA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 105 | 106 | 107 | 108 | > 意:这里客户端发送一个文件叫 **index.html**,服务器端以文件名 **xxx.html** 来保存,也就是说服务器端保存接收的文件名时不一定要使用客户端发送的文件名。 109 | 110 | 根据上面的介绍,当我们需要调试我们自己的服务器或者客户端程序时,又不想自己开发相应的对端,我们就可以使用 **nc** 命令去模拟。 111 | 112 | 当然,**nc** 命令非常强大,其功能远非本节介绍的这些,读者如果有兴趣可以去 **nc** 的 man 手册上获取更多的信息。 113 | -------------------------------------------------------------------------------- /articles/程序员必知必会的网络命令/README.md: -------------------------------------------------------------------------------- 1 | ## 程序员必知必会的网络命令 2 | 3 | 4 | 5 | * [利用telnet命令发电子邮件](利用telnet命令发电子邮件.md) 6 | 7 | * [做Java或者C++开发都应该知道的lsof命令](做Java或者C++开发都应该知道的lsof命令.md) 8 | 9 | * [Linux网络故障排查的瑞士军刀nc命令](Linux网络故障排查的瑞士军刀.md) 10 | 11 | * [Linux tcpdump使用详解](Linuxtcpdump使用介绍.md) 12 | 13 | * [从抓包的角度分析connect函数的连接过程](从抓包的角度分析connect函数的连接过程.md) 14 | 15 | * [服务器开发中网络数据分析与故障排查经验漫谈](服务器开发中网络数据分析与故障排查经验漫谈.md) 16 | 17 | -------------------------------------------------------------------------------- /articles/程序员的烦心事/README.md: -------------------------------------------------------------------------------- 1 | ## 程序员的烦心事 2 | 3 | * [拒绝了一家公司的offer后,他们的副总和hr总监同时打电话来询问拒绝原因并极力要求加入,我该不该去?](拒绝了一家公司的offer后,他们的副总和hr总监同时打电话来询问拒绝原因并极力要求加入,我该不该去?.md) 4 | 5 | * [我是一名程序员,结婚时女友要求我用两年的工资作为彩礼,我该不该答应?](我是一名程序员,结婚时女友要求我用两年的工资作为彩礼,我该不该答应?.md) 6 | 7 | -------------------------------------------------------------------------------- /articles/程序员的烦心事/我是一名程序员,结婚时女友要求我用两年的工资作为彩礼,我该不该答应?.md: -------------------------------------------------------------------------------- 1 | ## 我是一名程序员,结婚时女友要求我用两年的工资作为彩礼,我该不该答应? 2 | 3 | **以下内容来自于一名群友的求助,经当事人同意首发于**『高性能服务器开发』**公众号,文字略有改动,未经许可,不得转载。** 4 | 5 | (以下文中的“我”乃当事人本人,非文章作者。) 6 | 7 | > 群主,您好。我是一名上海一名 C++ 客户端开发,最近遇到了点私人问题,请群主帮我参考一下。以下是我的问题: 8 | > 9 | > **我是一名程序员,很爱我的女友,谈婚论嫁时,女友要求我用两年的工资作为彩礼,我该不该答应?** 10 | 11 | **(一)** 12 | 13 | 我老家是湖北黄石的,大学就读于武汉某学校,2018 年 7 月毕业,辗转来到上海。由于学历不太好,加上大学荒废了四年,在上海找了近一个月工作之后,终于 2018 年 7 月底上海找了一份 做 PC 客户端开发的工作,使用 C++ 语言。公司是做金融系统平台定制的,主要业务是股票交易系统,为此招了很多数据分析师,女孩子比较多。我就在这家公司认识了我现在的女朋友,她也是一名数据分析师,她是江苏人,也是在武汉上的学,大学毕业时在券商实习做过柜台,所以业务比较熟悉。平常她需要和我们这些开发进行对接,一来二去我们就熟悉了。有一次无意中一起下班,发现我们顺路,后来我们就经常一起加班下班,我向她请教业务问题,她和我了解系统实现逻辑。 14 | 15 | 后来一段时间,我发现她每天早上来的很晚,而且总是眼睛红红的或者像是没休息好的样子。于是,我趁着下班的机会,问她怎么了,可是她总是说没事。终于有一天晚上我们一起下班回家的日子,她告诉我原因了:她前男友那段时间总是打电话找她,请求复合,她已经和前男友分手快一年了,她前男友回了老家,她来到了上海。现在她男朋友生了病,据她描述应该病的不轻,她拒绝了他的复合要求,但是她心里觉得很过意不去,对于一个病人这样做是不是太残忍了。但是,她又不想复合,虽然她的前男友平常对她很好,但前男友是个喜怒无常且无任何人生规划的人,还有一点点家庭暴力倾向。(画外音:小方群主看到这里惊呆了,好狗血的剧情。。。) 16 | 17 | 后来,某天晚上在公司附近的公园的草坪上我不断的安慰她,让她想开一点,既然分手了,又有顾忌,就不要再想前一段感情了,建议她向前看。 18 | 19 | 又过了几天,她说她想通了,这次决定放下。那天晚上,我去了她租的房子。之前,她每次只允许我走到她小区门口,从不允许我进去,调侃我说我“图谋不轨”。那天晚上,我真是感到受宠若惊,聊的比较晚。后来不知道因为什么事情,她又说起了她的前男友如何可怜,我当时很生气,抓起我的书包就准备走。她突然一把抱住我,并且强吻了我。我当时就木头了,单身二十三年,女孩子手都没摸过,更不用说和女孩子接吻了。那感觉,当时脑子就不清醒了。然后,她反问我:XXX,你是不是想追我?我当时小心翼翼地回答是。她说让她考虑一下,然后就让我先回去了。 20 | 21 | 我一宿未眠,不知道她如何想的。第二天一大早就去了公司,可是一上午都没看到她来公司,我给她发微信打电话也没人回。终于,下午她终于来公司了,而且看起来精神状态不错。她神秘兮兮的和我说晚上一起吃饭。 22 | 23 | 晚上我们一起在公司的楼下食堂吃饭,她说她和她前男友好好的聊了一下,把事情说清楚了。她不会再想她的前男友,并且接受我的追求。那天,当她告诉我她愿意接受我的时候,我非常的开心。 24 | 25 | **(二)** 26 | 27 | 接下来的日子,应该是我人生中最开心的一段日子了。我发现,我们对文学都很感兴趣,我们一起聊《红楼梦》《雷雨》《巴黎圣母院》《飘》《百年孤独》《海上钢琴师》等一些国内外的经典著作和电影,她和我聊她之前在深圳和小伙伴们的趣事,还有一些我从未听过的文学作品,她的学识令我佩服。 28 | 29 | 那段时候,下班以后,我俩骑着共享单车在华师和同济大学的校园里漫游,有时候手拉手在河边散步,无话不谈,真的佩服她的文学素养和对世界的认识。而且让我惊喜的是,她有一手好厨艺,我琢磨着和她自小的家庭环境有关系吧。周末她烧饭时,从来不让我洗碗,而且一个人全包了从买菜到炒菜煮饭、饭后洗碗、打扫的全过程。我们一起玩王者荣耀和英雄联盟,她对这两个游戏也很感兴趣。 30 | 31 | 周末有的时候我们会一起去南京路步行街逛街、看看电影,我觉得她是个非常独立的人,她每次买东西都不会让我付钱,而且我之前断断续续借给她五六千块钱,在一次闹矛盾后也一分不少的还给我了。当然后来,我们又和好了。 32 | 33 | 在交往中,我知道了她的家庭状况。家在苏北农村,父母务农。家里有一个哥哥,高中没读完就辍学了。父母比较对哥哥比较宠爱,从小对她管不多,她经常和家里吵架。她从小的愿望就是将来离开家。所以她一个人去武汉上学,毕业后一个人去深圳,干了一年来到上海。但是,她的哥哥从小对他很好,她很感激。唉,这个"好"字,埋下了我后来的悲剧。 34 | 35 | 在一个周五的晚上,我们去了一家很有特色的古风饭店吃了顿饭,我们一起喝了点店里的招牌酒水——女儿红。她貌似喝醉了,脸红扑扑的,回来的路上,她一边挽着我的手一边给我唱王菲的情歌。那天星光下,她穿着一套白色的裙子,像个仙子一样美丽。那天,我也很开心,心里想:她的独立自强以及读了那么多书,具有一种一般女孩不具有的知性美,还有她的勤劳质朴,在现在的女大学生中实在太少了,这应该是我理想中的对象吧。 36 | 37 | 顺理成章,那天晚上,我们在她的租的房子里面发生了关系,我很意外的是,她竟然还是个chu。我问她后不后悔,她意味深长的问我,你知道女儿红这酒名的来历吗?我说不知道。她说,古时候,穷人家的父亲会在女儿出生的那一天,把一坛白酒用红色的布包好藏在地窖里,等女儿长大出嫁那一天会拿出来,送给出嫁的女儿和女婿。所以,她不后悔,并安慰我她爱我,这是迟早的事情。那天我暗暗下定决心,一定一辈子对她好。 38 | 39 | (三) 40 | 41 | 后来,有了第一次以后,我就经常在她那里过夜了,只不过我们隐藏的很好,公司没人知道我们的关系,我因为工作表现好,工资从六千涨到一万。后来,闲聊时,她和我说她哥哥对她的好,她虽然恨她的父母,但是她觉得她的哥哥挺可怜的,她想嫁给我,但希望我给她家 20 万的彩礼,她哥哥也可以拿着这笔钱娶老婆,她哥哥比她大五岁,她父母很着急,由于她哥哥学历不高没什么文化,又没啥手艺,生活过的很一般,年纪比较大了,家庭状况也不好,所以还没找到老婆,所以她父母压着她希望她在她哥哥的经济上照顾,她想着从小哥哥就照顾她,所以希望能帮哥哥一把。我当时听了这个话,不知道如何回答。20 万的彩礼对我来说,有点多,差不多相当于我现在快两年多的工资收入。我也是农村家庭,父母辛辛苦苦供我上大学。现在毕业了,父母年纪也大了,还有三万多的助学贷款没还完。 42 | 43 | 我带她回了趟老家,父母很满意,非常开心。在家里催婚的状况下,我尝试着和她沟通过很多次,能不能彩礼钱少一点,结婚本身也要花钱的,她似乎并不想让步。我不敢告诉我的父母,不想让他们本来很开心的心情泼一盆冷水。我很爱她,但是她的这个条件我确实有点为难。甚至有时候,我在想,本来好好的一场可以开花结果的恋爱,怎么感觉有种卖女儿的感觉? 44 | 45 | 另外还有件事,让我一直耿耿于怀,群主你不要笑(画外音:群主尽量忍住)。有次和她 XXOO 的时候,正在做的时候,她说她哥真的需要一个老婆,我有这方面的生理需求,她哥哥也有的。所以,她希望我能答应她的请求,她想和我过一辈子,但是希望我能理解下她,同意她的要求。我当时听了这话,像吃了苍蝇,立马没兴趣 XO 了。 46 | 47 | 这个月,她提出来双方父母见个面,希望我们可以定下来,可是我现在很纠结:我不想和她分手,我爱她,而且她的第一次给了我,但是我又不能满足她的彩礼要求。我不敢想这些事,现在上班也没心思。群主作为过来人和各位读者,能给我点建议吗? 48 | -------------------------------------------------------------------------------- /articles/程序员的烦心事/拒绝了一家公司的offer后,他们的副总和hr总监同时打电话来询问拒绝原因并极力要求加入,我该不该去?.md: -------------------------------------------------------------------------------- 1 | ## 拒绝了一家公司的offer后,他们的副总和hr总监同时打电话来询问拒绝原因并极力要求加入,我该不该去? 2 | 3 | **网友提问:** 4 | 5 | **拒绝了一家公司的offer后,他们的副总和hr总监同时打电话来询问拒绝原因并极力要求加入,我该不该去?** 6 | 7 | 面试的时候双方都感觉还可以,一面后hr开始压价,比预期低了3K,我拒绝。 8 | 9 | 然后邀请我去复试,跟经理交流后,觉得我可以,然而hr又压价,比预期低了1K,我拒绝,因为我对他们提出的期望薪资是我的最低底线。 10 | 11 | 然而过去不到1小时,hr说可以给到我期望薪资,并发了offer,但是试用期6个月打8折这个条件我不是很满意,而且offer居然没说明具体薪资组成部分,感觉他们很没诚意,然后思前想后决定发邮件拒绝了。 12 | 13 | 然而过去三天后,接到他们副总的电话,询问我拒绝原因,说自己公司管理制度如何如何人性化,还说条件可以再谈,非常诚恳也非常谦逊,感觉不好意思拒绝。然后我说自己再考虑考虑。随后hr再次电话来谈条件,说试用期不打折,并把薪资组成部分说的很详细,邀请我加入。 14 | 15 | 我犹豫了,现在有点纠结,手里还有另一家offer,待遇差不多,但是这家录用我很爽快,感觉我合适就直接发offer了,并说清楚了具体待遇。但是考虑这家公司目前规模和发展趋势不是符合自己预期的,所以也在犹豫中。 16 | 17 | 反正个人感觉第一家公司想要我但是却各种理由为难我,被我拒绝后又放低标准极力邀请我,这是不是一个坑啊,这么着急招人估计这个岗位肯定是个大坑啊。 18 | 19 | 现在很纠结,跳槽需要慎重考虑啊,真怕自己跳入一个更大的坑爬不出来。 20 | 21 | 22 | 23 | **小方老师建议:** 24 | 25 | 先说结论:**现在拿到offer的话,如果比较纠结就都不去,哪怕一家公司都去不了。再找就是了。** 26 | 27 | 说两段我的经验吧,第一段,几年前,在A公司和B公司之间两家公司的offer纠结,A公司离我住的地方太远不想去,B公司感觉氛围不太喜欢,最后在各种纠结中去了B公司,没干三个月受不了离职了。 28 | 29 | 某年年底找工作时,有个猎头,给我推荐了一个公司,我开始不太想去,因为这家公司我并不了解,所以我和猎头说,除非月薪可以给到30k,否则我不想去,后来猎头反复和对方公司沟通,最终满足了我的要求,但是,猎头说由于对方公司有一定的涨薪限制,所以不能给到月薪30k,但是由于我要求的是30k\*13薪,对方公司换了种方式,给26k\*15薪,这样一年下来也是39万。我开始是很不愿意这种所谓的变通方法,于是猎头就和他的领导那段时间反复做我的思想工作。我当时也非常纠结要不要去,因为相对于我当前的薪资确实翻了一番,但是我隐约觉得当初面试我的面试官(也就是我进去后我的直系领导)是个"不好相处"的人。后来猎头又反复和我说,面试我的面试官是和乐于传道受业解惑的和蔼可亲的技术大神最终在各种纠结中我还是去入职了。但是没过多久,我就干的很不开心。那个领导的代码风格稀烂,例如写C++代码,没有任何注释文档,甚至所有的实现文件都写在*.h文件中;其次,与人交流非常没耐心,下面的同事问他问题说不到三句可能就不耐烦,所以隔壁组的同事也都不太喜欢他,但是由于这个项目一直是他一个人做也没商业化,所以公司也没多管他。等到他带团队,与其他同事打交道时就暴露各种问题了。更让人受不了的是,他经常在项目要发版本时修改代码,也不通知其他同事,直到我们发现不对劲,排查很久发现问题,他才说。最让我们受不了的是,有次周六周日加了两天班,周六晚上到夜里十二点,周日到凌晨三点,他还冲团队成员发火。所以那天夜里,我四点钟半到家,直接给CTO写了封投诉他的信。 30 | 31 | 后来的情况不用说了,我当初面试的时顾虑都一一应验了,和我一起来的几个同事,年后都陆续离职了。 32 | 33 | 我想说的是,不管是薪资还是公司面试的时候面试官和人事的种种举动,如果你有顾虑或者觉得不适合你,千万不要为了钱本身就去了。 34 | 35 | 36 | 37 | > 小方老师联系方式:微信 easy_coder。 -------------------------------------------------------------------------------- /articles/程序员的简历/README.md: -------------------------------------------------------------------------------- 1 | ## 为什么你的简历没人看 2 | 3 | * [程序员如何写简历](程序员如何写简历.md) 4 | 5 | -------------------------------------------------------------------------------- /articles/程序员的薪资与年终奖那些事儿/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/程序员的薪资与年终奖那些事儿/.DS_Store -------------------------------------------------------------------------------- /articles/程序员的薪资与年终奖那些事儿/README.md: -------------------------------------------------------------------------------- 1 | ## 程序员的薪资与年终奖那些事儿 2 | 3 | * [技术面试与HR谈薪资技巧](技术面试与HR谈薪资技巧.md) 4 | 5 | * [聊一聊程序员如何增加收入](聊一聊程序员如何增加收入.md) 6 | 7 | * [谈一谈年终奖](谈一谈年终奖.md) 8 | 9 | -------------------------------------------------------------------------------- /articles/程序员面试题精讲/README.md: -------------------------------------------------------------------------------- 1 | ## 程序员面试题精讲 2 | 3 | * [腾讯后台开发实习生技能要求](腾讯后台开发实习生技能要求.md) 4 | 5 | * [聊聊如何拿大厂的 offer](聊聊如何拿大厂的offer.md) 6 | 7 | * [网络通信题目集锦](网络通信题目集锦.md) 8 | 9 | * [我面试后端开发经理的经历](我面试后端开发经理的经历.md) 10 | 11 | * [Linux C/C++后端开发面试问哪些问题](LinuxCC++后端开发面试问哪些问题.md) 12 | 13 | -------------------------------------------------------------------------------- /articles/程序员面试题精讲/网络通信题目集锦.md: -------------------------------------------------------------------------------- 1 | ## 网络通信面试题集锦 2 | 3 | 1. TCP/IP协议栈层次结构 4 | 5 | 2. TCP三次握手需要知道的细节点 6 | 7 | 3. TCP四次挥手需要知道的细节点(CLOSE_WAIT、TIME_WAIT、MSL) 8 | 9 | 4. TCP与UDP的区别与适用场景 10 | 11 | 5. linux常见网络模型详解(select、poll与epoll) 12 | 13 | 6. epoll_event结构中的epoll_data_t的fd与ptr的使用场景 14 | 15 | 7. Windows常见的网络模型详解(select、WSAEventSelect、WSAAsyncSelect) 16 | 17 | 8. Windows上的完成端口模型(IOCP) 18 | 19 | 9. 异步的connect函数如何编写 20 | 21 | 10. select函数可以检测网络异常吗? 22 | 23 | 11. epoll的水平模式和边缘模式 24 | 25 | 12. 如何将socket设置成非阻塞的(创建时设置与创建完成后设置),非阻塞socket与阻塞的socket在收发数据上的区别 26 | 27 | 13. send/recv(read/write)返回值大于0、等于0、小于0的区别 28 | 29 | 14. 如何编写正确的收数据代码与发数据代码 30 | 31 | 15. 发送数据缓冲区与接收数据缓冲区如何设计 32 | 33 | 16. socket选项SO_SNDTIMEO和SO_RCVTIMEO 34 | 35 | 17. socket选项TCP_NODELAY 36 | 37 | 18. socket选项SO_REUSEADDR和SO_REUSEPORT(Windows平台与linux平台的区别) 38 | 39 | 19. socket选项SO_LINGER 40 | 41 | 20. shutdown与优雅关闭 42 | 43 | 21. socket选项SO_KEEPALIVE 44 | 45 | 22. 关于错误码EINTR 46 | 47 | 23. 如何解决tcp粘包问题 48 | 49 | 24. 信号SIGPIPE与EPIPE错误码 50 | 51 | 25. gethostbyname阻塞与错误码获取问题 52 | 53 | 26. 心跳包的设计技巧(保活心跳包与业务心跳包) 54 | 55 | 27. 断线重连机制如何设计 56 | 57 | 28. 如何检测对端已经关闭 58 | 59 | 29. 如何清除无效的死链(端与端之间的线路故障) 60 | 61 | 30. 定时器的不同实现及优缺点 62 | 63 | 31. http协议的具体格式 64 | 65 | 32. http head、get与post方法的细节 66 | 67 | 33. http代理、socks4代理与socks5代理如何编码实现 68 | 69 | 34. ping 70 | 71 | 35. telnet 72 | 73 | 74 | 75 | 关于以上问题的答案,有兴趣可以参考我的知乎live:https://www.zhihu.com/lives/922110858308485120 76 | 77 | 78 | 79 | 或者如果你有任何不明白的地方,可以加我微信 **easy_coder** 交流。 -------------------------------------------------------------------------------- /articles/程序员面试题精讲/聊聊如何拿大厂的offer.md: -------------------------------------------------------------------------------- 1 | # 聊聊如何拿大厂的 offer 2 | 3 | ### 为什么要进大厂 4 | 5 | 许多读者,尤其是一些学生朋友在找我聊职业规划和职场困惑时,我给的建议就是,如果你是应届生或者工作年限较短(五年以下),那一定要找个机会去大厂工作几年。 6 | 7 | 无论是出于所谓的“镀镀金”的心理,还是想去大厂挑战大业务量、接触高并发、提高技术、开阔视野,都是非常值得的。 8 | 9 | 虽然很多大厂都加班,但是作为工薪阶层的一员,哪里不加班呢?再者大厂的各项规章制度和福利待遇都比较完善,你可以见识到很多成熟的系统和优秀的做法和理念。 10 | 11 | 就福利待遇来说,大厂给的薪资待遇比一般的小公司给的要高上一截。就算你从大厂离职,你也可以很容易的涨薪去另外一家大厂。这些都是小公司的没有的优势(我这里并不是说小公司不好)。 12 | 13 | 由于刚毕业的时候,没有能够进大厂,导致起点和平台都比同时间进大厂的同学低许多。虽然最终通过自己的努力,从刚毕业时的月薪 5 千到现在的年薪 50 W+。 14 | 15 | 这期间我走了很多弯路和吃了很多苦头。以工资收入来说,未进大厂的,可能在社会上摸爬滚打好多年才勉强达到月薪 2~3 万,而进大厂可能工作一两年就够了,甚至有些大厂开出的 SSP 直接就有三五十万。 16 | 17 | 因此,如果你一毕业就进入了大厂,那么你的第一份工作的收入、起点和视野就会比同龄人高很多。这也是我苦口婆心地劝毕业生们在毕业前夕的那段日子里面咬咬牙,努力去拿个大厂的 Offer 的原因。 18 | 19 | ### 进入大厂的难点在哪里 20 | 21 | 虽然大厂很好,但是进大厂对个人资质、个人素养和技术水平都有一定的要求,并不是每个人都有机会的。这里说的个人资质,如学历和毕业院校的层次。 22 | 23 | 一般大厂都只接收本科及本科以上的学历,对于本科以下的学历的应届生一般都不会考虑。而且会优先选择学校层次还不错的毕业生。 24 | 25 | 也就是说对于应届生,学校和学历成了硬性要求。即使你的能力再强,HR 筛选简历时就已经把你给 pass 掉了,你根本没有面试的机会。 26 | 27 | 高考已经没考好了,这个已经成为既成事实了。那对于学历和学校不好的人,还有机会补救吗? 28 | 29 | 有的,通过社招。 30 | 31 | 也就是说,你可以先工作几年,再尝试去大厂面试。因为社招更多的是看重的是你的技术水平、工作经验等,对学历要求没那么高了。 32 | 33 | ### 如何进入大厂 34 | 35 | 无论是应届生还是工作几年的人,一般都需要通过技术面试才能进入大厂。 36 | 37 | 那么大厂技术面试一般会哪些问题呢?除了少部分相关的技术外,重头戏都是算法与数据结构。 38 | 39 | 说到算法和数据结构这门学科,很多人尤其是已经工作了几年的社会人士,用范玮琪的一句歌词来形容,那真是“那一些是非题,总让人伤透脑筋”。 40 | 41 | 大家常学常忘,但为了面试,尤其是大厂面试,所以不得不学。 42 | 43 | 很多人对算法和数据结构这门课,甚至存在这样一个误解:实际工作中根本用不到算法,只有面试才会用到。产生这种错觉的原理,莫外乎此人技术不够资深、水平不够好,无缘参与核心开发而已。 44 | 45 | **学好算法和数据结构,无论对从技术水平长远的发展来说,还是对个人逻辑思维锻炼都是大有裨益的。** 46 | 47 | 国内的大厂面试,基本上大多数问题都是各种算法和数据结构题,而国外的大厂,像 Google、Facebook、微软等等,基本上百分之百是算法和数据结构题目。 48 | 49 | 很多应届毕业生横扫各大大厂 Offer,很大一部分原因是因为算法和数据结构掌握的好,当然薪资也非常可观。社会人士虽然在面试大厂时对相关的项目有一定的工作经验,没有像应届生要求那么高,但是最基础最常用的算法和数据结构还是要熟悉的。 50 | 51 | 说了这么多,那么大厂面试到底要求哪些算法和数据结构知识?我根据我面试的经验,给大家整理了一个清单: 52 | 53 | 1. **排序(常考的排序按频率排序为:****快速排序 > 冒泡排序 > 归并排序 > 桶排序)** 54 | 55 | 一般对于对算法基础有要求的公司,如果你是应届生或者工作经验在一至三年内,以上算法如果写不出来,给面试官的印象会非常不好,甚至直接被 pass 掉。 56 | 57 | 对于工作三年以上的社会人士,如果写不出来,但是能分析出其算法平均、最好和最坏的情况下的复杂度,说出算法大致原理,在多数面试官面前也可以过的。注意,如果你是学生,写不出来或者写的不对,基本上面试就过不了。 58 | 59 | 2. **二分查找** 60 | 61 | 二分查找的算法尽量要求写出来。当然,大多数面试官并不会直接问你二分查找,而是结合具体的场景,例如如何求一个数的平方根,这个时候你要能想到是二分查找。 62 | 63 | 我在 2017 年年底,面试 agora 时,面试官问了一个问题:如何从所有很多的 ip 地址中快速找个某个 ip 地址。 64 | 65 | 3. **链表** 66 | 67 | 无论是应届生还是工作年限不长的社会人士,琏表常见的操作一定要熟练写出来,如链表的查找、定位、反转、连接等等。还有一些经典的问题也经常被问到,如两个链表如何判断有环(我在 2017 年面试饿了么二面、上海黄金交易所一面被问过)。 68 | 69 | 链表的问题一般不难,但是链表的问题存在非常多的“坑”,如很多人不注意边界检查、空链表、返回一个链表的函数应该返回链表的头指针等等。 70 | 71 | 4. **队列与栈** 72 | 73 | 对于应届生来说一般这一类问的比较少,但是对于社会人士尤其是中高级岗位开发,会结合相关的问题问的比较多,例如让面试者利用队列写一个多线程下的生产者和消费者程序,全面考察的多线程的资源同步与竞态问题(下文介绍多线程面试题时详细地介绍)。 74 | 75 | 栈一般对于基础要求高的面试,会结合函数调用实现来问。即函数如何实现的,包括函数的调用的几种常见调用方式、参数的入栈顺序、内存栈在地址从高向低扩展、栈帧指针和栈顶指针的位置、函数内局部变量在栈中的内存分布、函数调用结束后,调用者和被调用者谁和如何清理栈等等 76 | 77 | 某年面试京东一基础部门,面试官让写从 0 加到 100 这样一个求和算法,然后写其汇编代码。 78 | 79 | 5. **哈希表** 80 | 81 | 哈希表是考察最多的数据结构之一。常见的问题有哈希冲突的检测、让面试者写一个哈希插入函数等等。基本上一场面试下来不考察红黑树基本上就会问哈希表,而且问题可浅可深。 82 | 83 | 我印象比较深刻的是,当年面试百度广告推荐部门时,二面问的一些关于哈希表的问题。 84 | 85 | 当时面试官时先问的链表,接着问的哈希冲突的解决方案,后来让写一个哈希插入算法,这里需要注意的是,你的算法中插入的元素一定要是通用元素,所以对于 C++ 或者 Java 语言,一定要使用模板这一类参数作为哈希插入算法的对象。 86 | 87 | 然后,就是哈希表中多个元素冲突时,某个位置的元素使用链表往后穿成一串的方案。 88 | 89 | 最终考察 Linux 下 malloc(下面的 ptmalloc) 函数在频繁调用造成的内存碎片问题,以及开源方案解决方案 tcmalloc 和 jemalloc。 90 | 91 | 总体下来,面试官是一步步引导你深入。(有兴趣的读者可以自行搜索,网上有很多相关资料) 92 | 93 | 6. **树 面试高频的树是红黑树,也有一部分是 B 树(B+ 树)。** 94 | 95 | 红黑树一般的问的深浅不一,大多数面试官只要能说出红黑树的概念、左旋右旋的方式、分析出查找和插入的平均算法复杂度和最好最坏时的算法复杂度,并不要写面试者写出具体代码实现。 96 | 97 | 一般 C++ 面试问 stl 的 map,java 面试问 TreeMap 基本上就等于开始问你红黑树了,要有心里准备。笔者曾经面试爱奇艺被问过红黑树。 98 | 99 | B树一般不会直接问,问的最多的形式是通过问 MySQL 索引实现原理。笔者面试腾讯看点部门二面被问到过。 100 | 101 | 7. **图** 102 | 103 | 图的问题我在面试三星电子时就有一道面试题就是深度优先和广度优先问题。 104 | 105 | 8. **其他的一些算法** 106 | 107 | 如 A* 寻路、霍夫曼编码也偶尔会在某一个领域的公司的面试中被问到,我在面试宝开(《植物大战僵尸》的母公司)就被问到过。 108 | 109 | -------------------------------------------------------------------------------- /articles/网络编程/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/网络编程/.DS_Store -------------------------------------------------------------------------------- /articles/网络编程/README.md: -------------------------------------------------------------------------------- 1 | ## 网络编程 2 | 3 | 4 | 5 | * [bind 函数重难点解析](bind函数重难点解析.md) 6 | 7 | * [connect 函数在阻塞和非阻塞模式下的行为](connect函数在阻塞和非阻塞模式下的行为.md) 8 | 9 | * [select 函数重难点解析](select函数重难点解析.md) 10 | 11 | * [Linux epoll 模型(含LT 模式和 ET 模式详解)](Linuxepoll模型(含LT模式和ET模式详解).md) 12 | 13 | * [socket 的阻塞模式和非阻塞模式](socket的阻塞模式和非阻塞模式.md) 14 | 15 | * [非阻塞模式下 send 和 recv 函数的返回值](非阻塞模式下send和recv函数的返回值.md) 16 | 17 | * [服务器开发通信协议设计介绍](服务器开发通信协议设计介绍.md) 18 | 19 | * [TCP 协议如何解决粘包、半包问题](TCP协议如何解决粘包、半包问题.md) 20 | 21 | * [网络通信中收发数据的正确姿势](网络通信中收发数据的正确姿势.md) 22 | 23 | * [服务器端发数据时,如果对端一直不收,怎么办?](服务器端发数据时,如果对端一直不收,怎么办?.md) 24 | 25 | -------------------------------------------------------------------------------- /articles/网络编程/服务器端发数据时,如果对端一直不收,怎么办?.md: -------------------------------------------------------------------------------- 1 | ## 服务器端发数据时,如果对端一直不收,怎么办? 2 | 3 | 这类问题一般出现在跨部门尤其是与外部开发人员合作的时候。假设现在有这样一种情况,我们的服务器提供对外的服务,指定好了协议,然后对外提供服务,客户端由外部人员去开发,由于存在太多的不确定性,如果我们在给对端(客户端)发送数据时,对端因为一些问题(可能是逻辑 bug 或者其他的一些问题)一直不从 socket 系统缓冲区中收取数据,而服务器端可能定期产生一些数据需要发送给客户端,再发了一段时间后,由于 TCP 窗口太小,导致数据发送不出去,这样待发送的数据会在服务器端对应的连接的发送缓冲区中积压,如果我们不做任何处理,很快系统就会因为缓冲区过大内存耗尽,导致服务被系统杀死。 4 | 5 | 对于这种情况,我们一般建议从以下几个方面来增加一些防御措施: 6 | 7 | 1. 设置每路发送连接的发送缓冲区大小上限(如 2 M,或者小于这个值),当某路连接上的数据发送不出去的时候,即将数据存入发送缓冲区时,先判断一下缓冲区最大剩余空间,如果剩余空间已经小于我们要放入的数据大小,也就是说缓冲区中数据大小会超过了我们规定的上限,则认为该连接出现了问题,关闭该路连接并回收相应的资源(如清空缓冲区、回收套接字资源等)。示例代码如下: 8 | 9 | ``` 10 | //outputBuffer_为发送缓冲区对象 11 | size_t remainingLen = outputBuffer_.remainingBytes(); 12 | //如果加入到缓冲区中的数据长度超出了发送缓冲区最大剩余量 13 | if (remainingLen < dataToAppend.length()) 14 | { 15 | forceClose() 16 | return 17 | } 18 | 19 | outputBuffer_.append(static_cast(dataToAppend.c_str()), dataToAppend.length()); 20 | ``` 21 | 22 | 2. 还有另外一种场景,当有一部分数据已经积压在发送缓冲区了,此后服务器端未产生新的待发送的数据,此时如果不做任何处理,发送缓冲区的数据会一直积压,但是发送缓冲区的数据容量也不会超过上限。如果不做任何处理的话,该数据会一直在缓冲区中积压,白白浪费系统资源。对于这种情况一般我们会设置一个定时器,每隔一段时间(如 3 秒)去检查一下各路连接的发送缓冲区中是否还有数据未发送出去,也就是说如果一个连接超过一定时间内还存在未发送出去的数据,我们也认为该连接出现了问题,我们可以关闭该路连接并回收相应的资源(如清空缓冲区、回收套接字资源等)。示例代码如下: 23 | 24 | ``` 25 | //每3秒检测一次 26 | const int SESSION_CHECK_INTERVAL = 3000; 27 | 28 | SetTimer(SESSION_CHECK_TIMER_ID, SESSION_CHECK_INTERVAL); 29 | 30 | void CSessionManager::OnTimer() 31 | { 32 | for (auto iter = m_mapSession.begin(); iter != m_mapSession.end(); ++iter) 33 | { 34 | if (!CheckSession(iter->value)) 35 | { 36 | //关闭session,回收相关的资源 37 | iter->value->ForceClose(); 38 | 39 | iter = m_mapSession.erase(iter); 40 | } 41 | } 42 | } 43 | 44 | void CSessionManager::CheckSession(CSession* pSession) 45 | { 46 | if (!pSession->GetConnection().OutputBuffer.IsEmpty()) 47 | return false; 48 | 49 | return true; 50 | } 51 | ``` 52 | 53 | 上述代码,每隔 3 秒检测所有的 Session 的对应的 Connection 对象,如果发现发送缓冲区非空,说明该连接中发送缓冲区中数据已经驻留 3 秒了,将该连接关闭并清理资源。 54 | -------------------------------------------------------------------------------- /articles/职业规划/README.md: -------------------------------------------------------------------------------- 1 | ## 职业规划 2 | 3 | * [给工作 4 年迷茫的程序员们的一点建议](给工作4年迷茫的程序员们的一点建议.md) 4 | 5 | * [聊聊技术人员的常见的职业问题](聊聊技术人员的常见的职业问题.md) 6 | 7 | * [写给那些傻傻想做服务器开发的朋友](写给那些傻傻想做服务器开发的朋友.md) -------------------------------------------------------------------------------- /articles/职业规划/写给那些傻傻想做服务器开发的朋友.md: -------------------------------------------------------------------------------- 1 | ## 写给那些傻傻想做服务器开发的朋友 2 | 3 | > 很久以前看过一篇标题为《[写给那些傻傻的,想做服务器开发的应届生](https://blog.csdn.net/likika2012/article/details/48972695)》文章,无意中看到知乎上也对这篇文章进行了激烈的讨论。下面谈谈我的看法。 4 | 5 | ### 写在前面的话 6 | 7 | 我在七八年前就看过这篇文章,那个时候我还是一名学生,它深深地影响了我学生时代以及后来的人生轨迹。(所以原文绝对不是首次发表于2015年,我猜想可能是后来的作者2015年修改了原作者的一些内容,并增加了一些自己的东西,让它"与时俱进")。我学生时代深受这篇文章的影响,以至于我印象中的服务器开发的样子和地位就是这篇文章中所描述的。 8 | 9 | ### 我的工作经历 10 | 11 | 我毕业的时候,一心想做出Windows C/C++客户端开发,当时为了做这个开发放弃了我熟悉的flash编程和web开发,当然薪资也是比较低的。做了几年Windows客户端后,我毅然以一定的代价转到了linux服务器开发。到今天为止,大致做过股票资讯、交易系统、游戏服务器、即时通讯系统和直播类型的服务器,架构的能力也由最初的千人到后来的百万在线。我从不后悔我当初转行服务器开发,甚至很庆幸当初的抉择,然而我可能更喜欢的还是客户端开发。 12 | 13 | 《`写给那些傻傻的,想做服务器开发的应届生`》一文中的有些观点,根据我的经历,我不敢赞同,或者说我的感受与之大相径庭。 14 | 15 | ### 加班的情况 16 | 17 | 首先说下加班的情况,不管是大公司还是小公司,由于现在的各种测试、预警机制、监控策略和公司发布流程的不断完善,一个月内经常为各种服务器bug、和应急的情况加班的现状已经大为改善不少,当然偶尔发版或者赶项目加班还是有的,不过一个月的频率也就那么一两次。如果你们团队频繁地为了修正紧急bug、解决服务器稳定性问题,那么你们真要好好考虑你们的方法是不是有问题了。 18 | 19 | ### 服务器开发与轮子 20 | 21 | 其次,服务器开发,不仅仅如文中所说的,利用或者组装各种轮子。一个稳定的服务器架构,必须是建立在设计师良好的基础知识和见多识广的经验基础上,即使是使用现有的轮子,也是对这个轮子足够熟悉的基础上,才能让轮子最大地适用自己的公司的业务。也就是说,服务器核心项目人员虽然不一定要造轮子,但一定要具备造轮子的能力。开源的东西好用是好用,但是要么不出问题,一旦出问题往往很难修改。我们去年做类似“冲顶大会”、“百万英雄”这类直播答题应用,由于这类游戏是从美国HQ刮过来的风,国内各大公司为了迅速抢占市场与用户,都想着要比别人早点做出来上线,所以我们公司当时deadline压得比较紧。我们那个时候,最不想看到的人就是项目经理,天天跟着我们后面催项目的进度。项目进度紧不说,另外还有一个技术挑战,由于节目比较火热,同一个房间里面可能会达到百万人同时在线,而这百万人可能同时都会发弹幕消息。假设某个时刻,房间里面有n个人,某个人发一条消息,其他n-1个人收到,服务器需要推送n-1次。如果n个人同时发消息,那么服务器同一时间就要推送n*n,如果n等于1百万的时候,那么单秒的数据量将非常恐怖,这个是我们需要解决的一个技术难题,解决目标是最少延迟的情况下,弹幕最多的送达率;另外一个难题就是,保证出题和答案不能有太多的延时(小于1秒),并在用户给出答案后,服务器能够迅速统计出答案结果并应答客户端。(没办法,所以此时主持人的作用就发挥了,万一延迟太厉害,主持人可以和观众各种唠嗑,当然这是下下策,如果频繁出现这种情况,领导的脸色肯定也不好看,我们做技术的脸上也没有光彩。)那段时间基本上是周六周日都要加班,甚至连周末都可能要到凌晨才能回去。注意:我把这段经历并没有放在上面的关于服务器开发是否频繁地加班的栏目下,这里我想说明的并不是服务器开发要经常加班,我想说的是,如果你平常只会用轮子,而不注重基础内功的修养,这种场景你是很难应对的,首先是单机服务性能要做到极致,其次是多个服务之间的高效配合。很多人可能觉得这种场景也不难,甚至有的人号称单机服务就能解决,这些都是站着说话不腰疼了。像熊猫tv的“冲顶大会”和西瓜视频的“百万英雄”前几次的答题活动中,也出现了服务中断或者题目延迟厉害,甚至“百万英雄”还出现过一次因技术问题答题活动被迫延期的事故。 22 | 23 | ### 技术与产品思维 24 | 25 | 接着说下,技术和产品方面的,服务器开发与客户端开发的思维方式和理念其实是不一样的,如果说客户端产品是一个产品的脸面,那么服务器端就是产品的灵魂。这里可能比喻有点不恰当,与客户端开发相比,优秀的服务器开发应该尽量在单机服务上的性能做到极致,必须尽量利用少的资源给尽可能多的客户端服务(在资源总量有限的情况下,你为单个客户端服务使用的资源越少,你才可能为越多的客户服务)。而服务器开发必须有条不紊地处理与每个客户端的交互,不能纠结或把资源花费在某一个客户端上。但是客户端不一样,客户端只需要管理好自己的一亩三分地就可以了,而且客户端的大多数逻辑和细节在界面(UI)逻辑上。但是我不赞成文中作者所说的客户端代码比服务器代码少很多,相反,我经历过的项目,都是客户度代码比服务器代码多很多。因为客户端代码往往有大量的界面逻辑,如果服务器端没有UI的话,其核心除了网路通信部分,剩下的就是各种业务逻辑(包括存储逻辑,也就是业务逻辑服务器和客户端都有,但是客户端还有界面逻辑)。而从开发团队的人数配比上来说,一般单个端(比如pc、安卓、ios中的一端)的人数要小于服务器开发人员的数量,因为一般一个高级客户端开发,往往可以一个人搞定一个客户端,但是一般很少有一个高级服务器开发可以单独搞定一套服务开发的。(说的是通常情形,请不要走极端)。服务器开发的核心字眼体现在“服务”上,如何为客户端提供稳定的、高效的服务,这是关键的地方。这里“稳定”也包括容灾容错。大凡有一定规模的用户群体的产品,如果服务器不稳定,那后果将是灾难性的,试想QQ或者微信服务器中断一两个小时,后果会怎样?而客户端更侧重的就是产品的细节、用户的体验,当然尽管有些用户体验可能是由服务器端决定的,但是最终还是由客户端反映出来。我不赞同文章中说,客户端更能积累除了技术以外的其他知识,服务器开发也一样的,不管是客户端还是服务器,只有具有产品思维的开发才是好的开发,而功能的设计与规划服务器端的开发在时间点上一般先于客户端开发的。而具体的功能点,也是需要服务器开发人员与产品人员乃至客户沟通的。 26 | 27 | ### 薪资方面 28 | 29 | 最后说下,薪资方面。一般大于两年且同样的工作年限的服务器开发人员要比客户端开发人员高至少三分之一左右。当然不排除一些非常优秀的客户端开发人员可能不在这个规则内。 30 | 31 | ### 结语 32 | 33 | 总结起来,选择了哪条路就选择了什么样的生活。做服务器开发的可以在高并发、高可用方向进一步努力,而做客户端开发可以在用户体验、设计细节方面下功夫。不管怎样,都是我们想要的生活,那里倾洒了我们的汗水,也收获了我们自己的成就感。 34 | -------------------------------------------------------------------------------- /articles/职业规划/给工作4年迷茫的程序员们的一点建议.md: -------------------------------------------------------------------------------- 1 | ## 给工作 4 年迷茫的程序员们的一点建议 2 | 3 | 有公众号读者在后台向我提问: 4 | 5 | > JAVA 程序员,4 年了,迷茫了,希望由前辈可以给指出一个技术路线5年左右程序员必须要掌握的知识技能树? 6 | > 7 | > 工作了很久了,对于目前自己的技术程度不满意,但是不知道如何梳理。学习一些技术是不知道是否有用。希望前辈可以指点迷津。不以年限轮英雄,希望可以给出您的见解。修改一次。。。。。。项目设计都是我来做。。。数据库设计也是我来做。。。我的意思是。。感觉目前自己的知识储备不足以支撑我架构以及设计。。求个知识树。。。。 8 | 9 | **以下是我的回答:** 10 | 11 | 先举两个真实的例子。 12 | 13 | **例子一:** 14 | 前两天我在给我们部门做服务器网络故障排查经验分享时,我问了一个问题关于 java.io.DataOutputStream 的问题,如果从一个 socket 输出流中读取数据,如果当前流中没有数据,读方法是否会阻塞。我又问,假如阻塞,会阻塞多久?我们如何避免这个问题。很多人回答不上来,更不用说,Java 中的 AIO、NIO 的使用细节了。 15 | 16 | **例子二:** 17 | 我归纳一下,情况大致如下: 18 | 有不少朋友通过我的公众号『**高性能服务器开发**』中的『职业指导』模块找到我,来意大致是:做 java 开发工作了三五年了,月收入不到二万,现在因为人到中年,经济压力比较大; 但是工作上只能做做模块,写写业务代码,所以即使跳槽也不会拿到满意的薪资,所以只好维持现状(但又特别苦闷、迷茫)。 19 | 20 | 我来说一下我的观点,说的现实一点,题主所谓的迷茫其实因知识能力的不足导致的成就感、收入水平与日益增长的工作年限的矛盾。 21 | 22 | 越是高薪的职位,其对人的要求也越高。诸如上面的例子,工作有几年的 java 开发者,连 jdk 中基本的输入输出流的细节都搞不清楚,一问到就是各种摇头,然后说各种 java 框架,这样的开发者其实并不合格,因为他们离开了框架就啥也做不了,那么在工作安排上这样的人不天天也业务代码,谁来写呢?(核心的技术框架是不能让他们写的,由于基础水平不扎实,写出来的框架稳定性和性能会不好)。说的悲观一点,这样的开发者公司是从来不缺的,铁打的营盘,流水的兵,走了再招一批罢了,这也就是所谓的千军易得一将难求,我们要努力做将才乃至帅才,而不是小兵。 23 | 24 | 在面试某些 java 开发者时,我问的比较多的一个问题就是,java 多线程之间的同步技术有哪些,然后不少面试者就病急乱投医了,甚至连 ConcurrentHashMap 都说上了。这也是典型的基础概念模糊不清,ConcurrentHashMap 是一个线程安全性容器,但绝不是一个线程同步技术。 25 | 26 | 再比如问面试者 java.lang.Object 有哪些常用方法时,不少面试者能说出来的也不多。 27 | 28 | 我举这些例子并不是为了要教大家具体的 java 知识,而是为了说明基础知识的重要性。如果你的java基础足够好(熟悉 jdk 的常用类,知道常用接口的各种坑和注意事项),那么开发一个东西时即使不用框架你也能顺畅地写出来。这样的人才具备进一步发展的潜力。退一步说,不管多么复杂的java框架,都是基于jdk那些类库的。你jdk的基础知识都学不好,我不相信那些上层框架你能搞的透彻。 29 | 30 | 说一千道一万,核心的还是基础知识不扎实的问题。就和刘备当年成就帝业一样,诸葛亮给的策略就是先谋取荆州,再进军西蜀,最后三分天下。同理jdk的基础知识就是你应该要首先谋取的“荆州”,进一步的各种框架、架构设计是你的“蜀地”。基础不牢,想其他的东西都是好高骛远,不切实际。最后日复一日,年复一年,在恨自己生不逢时,领导不是伯乐的嗟叹中蹉跎了岁月。 31 | 32 | 对于上面这个注重基础的问题上,实际情形中,我遇到三种人。 33 | 34 | 第一类:**意识不到基础知识的重要性,这类人就不提了。** 35 | 36 | 第二类,**意识到基础知识的重要性,但是总是在各种理由和借口中麻痹自己,温水煮青蛙把自己“煮死”。很多咨询我的人,也是这种情况,说什么自己工作忙,家庭琐事多。我其实不想多说啥,为失败找借口的人太多,为成功找方法的人太少。你工作五年了,每个月抽一天时间来补一下基础,你现在都不是这样了,这个时间也抽不出来?自我麻痹而已。这类人其实是有想法没啥行动。** 37 | 38 | 第三类,**意识到基础的重要性,同时在各种闲暇时间去补充,去积累。这样的人学的最快,最后达到的高度也很高(当然收入也不菲)。** 39 | 40 | **扎实的基础知识 + 见多识广的框架**经验,让你在职场上变得无可替代,这才是你的核心竞争力。答案可能有点跑题了,但是我觉得先解决思想上的问题,行动上就容易许多了。 41 | 42 | > 如果你想和我聊聊职业上的困惑,可以在『高性能服务器开发』公众号后台回复关键字『职业指导』,我们可以针对性地聊一聊。 -------------------------------------------------------------------------------- /articles/自我提升与开源代码/README.md: -------------------------------------------------------------------------------- 1 | ## 自我提升与开源代码 2 | 3 | * [2020 年好好读一读开源代码吧](2020年好好读一读开源代码吧.md) 4 | 5 | -------------------------------------------------------------------------------- /articles/高性能服务器框架设计/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/CppGuide/89a436edf939d951525b08367e4030125653b82c/articles/高性能服务器框架设计/.DS_Store -------------------------------------------------------------------------------- /articles/高性能服务器框架设计/README.md: -------------------------------------------------------------------------------- 1 | ## 高性能服务器框架设计 2 | 3 | * [主线程与工作线程的分工](主线程与工作线程的分工.md) 4 | 5 | * [Reactor模式](Reactor模式.md) 6 | 7 | * [实例:一个服务器程序的架构介绍](实例:一个服务器程序的架构介绍.md) 8 | 9 | * [错误码系统的设计](错误码系统的设计.md) 10 | 11 | * [日志系统的设计](日志系统的设计.md) 12 | 13 | * [如何设计断线自动重连机制](如何设计断线自动重连机制.md) 14 | 15 | * [心跳包机制设计详解](心跳包机制设计详解.md) 16 | 17 | * [业务数据处理一定要单独开线程吗](业务数据处理一定要单独开线程吗.md) 18 | 19 | * [C++ 高性能服务器网络框架设计细节](C++高性能服务器网络框架设计细节.md) -------------------------------------------------------------------------------- /articles/高性能服务器框架设计/主线程与工作线程的分工.md: -------------------------------------------------------------------------------- 1 | ## 主线程与工作线程的分工 2 | 3 | 服务器端为了能流畅处理多个客户端链接,一般在某个线程A里面accept新的客户端连接并生成新连接的socket fd,然后将这些新连接的socketfd给另外开的数个工作线程B1、B2、B3、B4,这些工作线程处理这些新连接上的网络IO事件(即收发数据),同时,还处理系统中的另外一些事务。这里我们将线程A称为主线程,B1、B2、B3、B4等称为工作线程。工作线程的代码框架一般如下: 4 | 5 | ``` 6 | while (!m_bQuit) 7 | { 8 | epoll_or_select_func(); 9 | 10 | handle_io_events(); 11 | 12 | handle_other_things(); 13 | } 14 | ``` 15 | 16 | 在epoll_or_select_func()中通过select()或者poll/epoll()去检测socket fd上的io事件,若存在这些事件则下一步handle_io_events()来处理这些事件(收发数据),做完之后可能还要做一些系统其他的任务,即调用handle_other_things()。 17 | 18 | 这样做有三个好处: 19 | 20 | 1. 线程A只需要处理新连接的到来即可,不用处理网络IO事件。由于网络IO事件处理一般相对比较慢,如果在线程A里面既处理新连接又处理网络IO,则可能由于线程忙于处理IO事件,而无法及时处理客户端的新连接,这是很不好的。 21 | 22 | 2. 线程A接收的新连接,可以根据一定的负载均衡原则将新的socket fd分配给工作线程。常用的算法,比如round robin,即轮询机制,即,假设不考虑中途有连接断开的情况,一个新连接来了分配给B1,又来一个分配给B2,再来一个分配给B3,再来一个分配给B4。如此反复,也就是说线程A记录了各个工作线程上的socket fd数量,这样可以最大化地来平衡资源,避免一些工作线程“忙死”,另外一些工作线程“闲死”的现象。 23 | 24 | 3. 即使工作线程不满载的情况下,也可以让工作线程做其他的事情。比如现在有四个工作线程,但只有三个连接。那么线程B4就可以在handle_other_thing()做一些其他事情。 25 | 26 | 27 | 28 | 下面讨论一个很重要的效率问题: 29 | 30 | 在上述while循环里面,epoll_or_selec_func()中的epoll_wait/poll/select等函数一般设置了一个超时时间。如果设置超时时间为0,那么在没有任何网络IO时间和其他任务处理的情况下,这些工作线程实际上会空转,白白地浪费cpu时间片。如果设置的超时时间大于0,在没有网络IO时间的情况,epoll_wait/poll/select仍然要挂起指定时间才能返回,导致handle_other_thing()不能及时执行,影响其他任务不能及时处理,也就是说其他任务一旦产生,其处理起来具有一定的延时性。这样也不好。那如何解决该问题呢? 31 | 32 | 其实我们想达到的效果是,如果没有网络IO时间和其他任务要处理,那么这些工作线程最好直接挂起而不是空转;如果有其他任务要处理,这些工作线程要立刻能处理这些任务而不是在epoll_wait/poll/selec挂起指定时间后才开始处理这些任务。 33 | 34 | 我们采取如下方法来解决该问题,以linux为例,不管epoll_fd上有没有文件描述符fd,我们都给它绑定一个默认的fd,这个fd被称为唤醒fd。当我们需要处理其他任务的时候,向这个唤醒fd上随便写入1个字节的,这样这个fd立即就变成可读的了,epoll_wait()/poll()/select()函数立即被唤醒,并返回,接下来马上就能执行handle_other_thing(),其他任务得到处理。反之,没有其他任务也没有网络IO事件时,epoll_or_select_func()就挂在那里什么也不做。 35 | 36 | 这个唤醒fd,在linux平台上可以通过以下几种方法实现: 37 | 38 | 1. 管道pipe,创建一个管道,将管道绑定到epoll_fd上。需要时,向管道一端写入一个字节,工作线程立即被唤醒。 39 | 40 | 2. linux 2.6新增的eventfd: 41 | 42 | ``` 43 | int eventfd(unsigned int initval, int flags); 44 | ``` 45 | 46 | 步骤也是一样,将生成的eventfd绑定到epoll_fd上。需要时,向这个eventfd上写入一个字节,工作线程立即被唤醒。 47 | 48 | 49 | 50 | 3. 第三种方法最方便。即linux特有的socketpair,socketpair是一对相互连接的socket,相当于服务器端和客户端的两个端点,每一端都可以读写数据。 51 | 52 | ``` 53 | int socketpair(int domain, int type, int protocol, int sv[2]); 54 | ``` 55 | 56 | 57 | 58 | 调用这个函数返回的两个socket句柄就是sv[0],和sv[1],在一个其中任何一个写入字节,在另外一个收取字节。 59 | 60 | 将收取的字节的socket绑定到epoll_fd上。需要时,向另外一个写入的socket上写入一个字节,工作线程立即被唤醒。如果是使用socketpair,那么domain参数一定要设置成AFX_UNIX。 61 | 62 | 由于在windows,select函数只支持检测socket这一种fd,所以Windows上一般只能用方法3的原理。而且需要手动创建两个socket,然后一个连接另外一个,将读取的那一段绑定到select的fd上去。这在写跨两个平台代码时,需要注意的地方。 63 | 64 | -------------------------------------------------------------------------------- /articles/高性能服务器框架设计/如何设计断线自动重连机制.md: -------------------------------------------------------------------------------- 1 | ## 如何设计断线自动重连机制 2 | 3 | 在有连接依赖关系的服务与服务之间,或客户端与服务器之间,无论是出于方便使用、降低运维成本、提高工作效率(服务与服务之间),还是优化用户体验(客户端与服务器之间)自动重连机制通常都是一个非常重要的功能。 4 | 5 | - 情景一 6 | 7 | 对于一组服务之间,如果其中一些服务(主动连接方,下文以 A 代称)需要与另外一些服务(被连接方,下文以 B 代称)建立 TCP 长连接,如果 A 没有自动连接 B 的功能,那么在部署或者测试这些服务的时候,必须先启动 B,再启动 A,因为一旦先启动 A,A 此时去尝试连接 B(由于 B 还没有启动)会失败,之后 A 再也不会去连接 B了(即使随后 B 被启动了),从而导致整个系统不能正常工作。这是缺点一。 8 | 9 | - 情景二 10 | 11 | 即使部署或测试的时候,先启动了 B,再启动 A,A 与 B 之间的连接在运行期间内,可能由于网络波动等原因导致 A 与 B 之间连接断开,之后整个系统也不能再正常工作了。这是缺点二。 12 | 13 | - 情景三 14 | 15 | 如果我们想升级 B,更新完程序后,重启 B,也必须重启 A。如果这种依赖链比较长(例如 A 连接 B,B 连接 C,C 连接 D,D 连接 E,等等),那么更新某个程序的效率和成本会非常高。这是缺点三。 16 | 17 | - 情景四 18 | 19 | 对于客户端软件来说,如果因为用户的网络短暂故障导致客户端与服务器失去连接,等网络恢复后,较好的用户体验是客户端能检测到用户网络变化后,自动与服务器重连,以便用户能及时收到最新的消息。 20 | 21 | 以上四个情景说明了断线自动重连功能的重要性,那如何去设计好的断线重连机制呢? 22 | 23 | 重连本身的功能开发很简单,其实就是调用 socket 函数 connect 函数,不断去“**重试**”。这里的“**重试**”我使用了双引号,是为了说明重试的技巧非常有讲究: 24 | 25 | - 对于服务器端程序,例如 A 连接 B,如果连接不上,整个系统将无法工作,那么我们开发 A 服务时,重连的逻辑可以很简单,即 A 一旦发现与 B 断开了连接,就立即尝试与 B 重新连接,如果连接不上,隔一段时间再重试(一般设置为 3 秒或 5 秒即可),一直到连接成功为止。当然,期间可以不断发送报警邮件或者持续输出错误日志,来引起开发或者运维人员的尽快干预,以便尽早排查和解决连接不上的原因。 26 | - 对于客户端软件,以上做法也是可以的,但是不是最优的。客户端所处的网络环境比服务器程序所处的网络环境一般要恶劣的多,等间隔的定时去重连,一般作用不大(例如用户拔掉了网线)。因此,对于客户端软件,一般出现断线,会尝试去重连,如果连接不上,会隔个比前一次时间更长的时间间隔去重连,例如这个时间间隔可以是 2 秒、4 秒、8 秒、16秒等等。但是,这样也存在一个问题,随着重连次数的变多,重连的时间间隔会越来越大(当然,你也可以设置一个最大重连时间间隔,之后恢复到之前较小的时间间隔)。如果网络此时已经恢复(例如用户重新插上网线),我们的程序需要等待一个很长的时间间隔(如 16 秒)才能恢复连接,这同样不利于用户体验。一般情况下,如果网络发生波动,我们的程序可以检测网络状态,如果网络状态恢复正常此时应该立即进行一次重连,而不是一成不变地按照设置的时间间隔去重连。 27 | 28 | > 操作系统提供了检测网络状态变化的 API 函数,例如对于 Windows 可以使用 IsNetworkAlive() 函数去检测,对于 Android,网络变化时会发送消息类型是 WifiManager.NETWORK_STATE_CHANGED_ACTION 的广播通知。 29 | 30 | 另外,还需要注意的是,如果客户端网络断开,一般会在界面某个地方显式地告诉用户当前连接状态,并提醒当前正在进行断线重连,且应该有一个可以让用户放弃断线重连或者立即进行一次断线重连的功能。 31 | 32 | 综上所述,总结起来,对于服务器程序之间的重连可以设计成等时间间隔的定时重连,对于客户端程序要结合依次放大重连时间间隔、网络状态变化立即重连或用户主动发起重连这三个因素来设计。 33 | 34 | #### 不需要重连的情形 35 | 36 | 不需要重连一般有以下情形: 37 | 38 | - 用户使用客户端主动放弃重连; 39 | 40 | - 因为一些业务上的规定,禁止客户端重连; 41 | 42 | 举个例子,如果某个系统同一时刻同一个账户只允许登陆一个,某个账户在机器 A 上登陆,此时接着又在机器 B 上登陆,此时 A 将被服务器踢下线,那么此时 A 客户端的逻辑就应该禁止自动重连。 43 | 44 | #### 技术上的断线重连和业务上的断线重连 45 | 46 | 这里说的技术上的重连,指的是调用 connect 函数连接,在实际开发中,大多数系统光有技术上的重连成功(即 connect 连接成功)是没有任何意义的,网络连接成功以后,接下来还得再次向服务器发送账号验证信息等等(如登陆数据包),只有这些数据验签成功后,才能算是真正的重连成功,这里说的发送账号验证信息并验签成功就是业务上的重连成功。复杂的系统可能会需要连续好几道验签流程。因此,我们在设计断线重连机制的时候,不仅要考虑技术上的重连,还要考虑业务上的重连。只有完整地包含这两个流程,才算是较优的断线自动重连功能。 47 | 48 | 本节介绍的知识点主要是思路性的内容,一旦搞清楚了思路,技术上实现起来并不会存在什么困难,因此本节没有给出具体的代码示例。 49 | 50 | 51 | 52 | 欢迎关注公众号『easyserverdev』,本公众号推崇基础学习与原理理解,不谈大而空的架构与技术术语,分享接地气的服务器开发实战技巧与项目经验,实实在在分享可用于实际编码的编程知识。同时,您也可以加入我的 QQ 群578019391。 53 | 54 | ![img](https://mmbiz.qpic.cn/mmbiz_jpg/TufFCFqd0g3oHvEeRbexpMHScvgbX64bxHD1jetjyVEESJp1E29nuiclygz4o10lpbCMujK6GaG7ot86ugWibBqw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 55 | 56 | 文章已于2019-08-12修改 -------------------------------------------------------------------------------- /articles/高性能服务器框架设计/错误码系统的设计.md: -------------------------------------------------------------------------------- 1 | ## 错误码系统的设计 2 | 3 | > 本文介绍服务器开发中一组服务中错误码系统的设计理念与实践,如果读者从来没想过或者没接触过这种设计理念,建议认真体会一下这种设计思路的优点。 4 | 5 | #### 错误码的作用 6 | 7 | 读者如果有使用过中国电信的宽带账号上网的经历,如果我们登陆不成功,一般服务器会返回一个错误码,如651、678。然后,我们打中国电信的客服电话,客服会询问我们错误码是多少,通过错误码他们的技术人员就大致知道了错误原因;并且通过错误码,他们就知道到底是电信的服务器问题还是宽带用户自己的设备或者操作问题,如果是用户自己的问题,他们一般会尝试教用户如何操作,而不是冒然就派遣维修人员上门,这样不仅能尽早解决问题同时也节约了人力成本。 8 | 9 | 再举另外一个例子,我们日常浏览网页,当Web服务器正常返回页面时,状态码一般是200(OK),而当页面不存在时,错误码一般是404,另外像503等错误都是比较常见的。 10 | 11 | 通过以上两个例子,读者应该能明白,对于服务器系统来说,设计一套好的错误码是非常有必要的,可以在用户请求出问题时迅速定位并解决问题。具体包括两个方面: 12 | 13 | 1. 可以迅速定位是用户“输入”问题还是服务器自身的问题。 14 | 15 | 所谓的用户“输入”问题,是指用户的不当操作,这里的“用户的不当操作”可能是因为客户端软件本身的逻辑错误或漏洞,也可能是使用客户端的人的非法操作,而客户端软件在设计上因为考虑不周而缺乏有效性校验,这两类情形都可能会产生非法的数据,并且直接发给服务器。一个好的服务端系统不能假设客户端的请求数据一定是合法的,必须对传过来的数据做有效性校验。服务器没有义务一定给非法的请求做出应答,因此请求的最终结果是服务器不应答或给客户端不想要的应答。 16 | 17 | 以上面的例子为例,宽带用户输入了无效的用户名或者密码造成服务器拒绝访问;用户在浏览器中输入了一个无效的网址等。这类错误,都是需要用户自己解决或者用户可以自己解决的。如果错误码可以反映出这类错误,那么在实际服务器运维的过程中,当用户反馈这一类故障时,我们通过服务器内部产生的错误码或者应答给客户端的错误码,准确快速地确定问题原因。如果是用户非法请求造成的,可以让用户自行解决。注意,这里的“用户”,可以代指人,也可以代指使用某个服务器的所有下游服务和客户端。 18 | 19 | 1. 可以快速定位哪个步骤或哪个服务出了问题。 20 | 21 | 对于单个服务,假设收到某个“客户端”请求时,需要经历多个步骤才能完成,而这中间任何一个步骤都可能出问题,在不同步骤出错时返回不同的错误码,那么就可以知道是哪个步骤出了问题。 22 | 23 | 其次,一般稍微复杂一点的系统,都不是单个服务,往往是由一组服务构成。如果将错误码分段,每个服务的错误码都有各自的范围,那么通过错误码,我们也能准确地知道是哪个服务出了问题。 24 | 25 | #### 错误码系统设计实践 26 | 27 | 前面介绍了太多的理论知识,我们来看一个具体的例子。假设如下一个“智能邮件系统”,其结构如下所示: 28 | 29 | ![](../imgs/errorsys1.png) 30 | 31 | 32 | 33 | 上图中的服务**“智能邮件坐席站点”**和**“配置站点”**是客户端,**”智能邮件操作综合接口“**和**”邮件配置服务“**是对客户端提供服务的前置服务,这两个前置服务后面还依赖后面的数个服务。由于这里我们要说明的是技术问题,而不是业务问题,所以具体每个服务作何用途这里就不一一介绍了。在这个系统中,当客户端得到前置服务某个不正确应答时,会得到一个错误码,我们按以下规则来设计错误码: 34 | 35 | | 服务名称 | 正值错误码范围 | 负值错误码范围 | 36 | | :------------------: | :------------: | :------------: | 37 | | 智能邮件综合操作接口 | 100~199 | -100~-199 | 38 | | ES数据同步服务 | 200~299 | -200~-299 | 39 | | 邮件配置服务 | 300~399 | -300~-399 | 40 | | 邮件基础服务 | 400~499 | -400~-499 | 41 | 42 | 我们在设计这套系统时,做如下规定: 43 | 44 | 1. **所有的正值错误码表示所在服务的上游服务发来的请求不满足业务要求**。举个例子,假设某次**智能邮件坐席站点**客户端得到了一个错误码**101**,我们可以先确定错误产生的服务器是**智能邮件综合操作接口**服务;其次,产生该错误的原因是**智能邮件坐席站点**客户端发送给**智能邮件综合操作接口**服务的请求不满足要求,通过这个错误码我们甚至可以进一步确定发送的请求哪里不符合要求。如我们可以这样定义: 45 | 46 | - 100 用户名不存在 47 | 48 | - 101 密码无效 49 | 50 | - 102 发送的邮件收件人非法 51 | 52 | - 103 邮件正文含有非法字符 53 | 54 | 其他从略,此处就不一一列举了。 55 | 56 | 1. **所有的负值错误码表示程序内部错误**。如: 57 | 58 | - -100 数据库操作错误 59 | 60 | - -101 网络错误 61 | 62 | - -102 内存分配失败 63 | 64 | - -103 **ES数据同步服务**连接不上 65 | 66 | 其他从略,此处就不一一列举了。 67 | 68 | #### 对负值错误码的特殊处理 69 | 70 | 通过前面的介绍,读者应该能看出正值错误码与负值错误码的区别,即正值错误码一般是由请求服务的客户产生,如果出现这样的错误,应该由客户自己去解决问题;而负值错误码,则一般是服务内部产生的错误。因此,如果是正值错误码,**错误码**和**错误信息**一般可以直接返回给客户端;而对于负值错误,我们一般只将**错误码**返回给客户端,而**不带上具体的错误信息**,这也是读者在使用很多软件产品时,经常会得到“**网络错误**”这类万能错误提示。也就是说对于负值错误码的错误信息,我们可以统一显示成“**网络错误**”或者其他比较友好的错误提示。 71 | 72 | 这样做的原因有二: 73 | 74 | 1. 客户端即使拿到这样的错误信息,也不能对排查和解决问题提供任何帮助,因为这些错误是程序内部错误或者bug。 75 | 2. 这类错误有可能是企业内部的设计缺陷,直接暴露给客户,除了让客户对企业的技术实力产生质疑以外,没有任何其他正面效应。 76 | 77 | 而之所以带上错误码,是为了方便内部排查和定位问题。当然,现在的企业服务,内部也有大量监控系统,可能也不会再暴露这样的错误码了。 78 | 79 | #### 扩展 80 | 81 | 上文介绍了利用错误码的分段来定位问题的技术思想,其实不仅仅是错误码可以分段,我们在开发一组服务时,业务类型也可以通过编号来分段,这样通过业务号就能知道归属哪个服务了。 82 | 83 | 如果读者以前没接触过这种设计思想,希望可以好好的思考和体会一下。 84 | --------------------------------------------------------------------------------