Linux多线程服务端编程

当前位置:首页 > 网络编程 > 编程语言与程序设计 > Linux多线程服务端编程

出版社:电子工业出版社
出版日期:2013-1-15
ISBN:9787121192821
作者:陈硕
页数:610页

章节摘录

版权页:   插图:   谈一谈网络编程学习经验 本文谈一谈我在学习网络编程方面的一些个人经验。“网络编程”这个术语的范围很广,本文指用Sockets API 开发基于TCP/IP 的网络应用程序,具体定义见§A.1.5 “网络编程的各种任务角色”。 受限于本人的经历和经验,本附录的适应范围是: x86-64 Linux 服务端网络编程,直接或间接使用Sockets API。 公司内网。不一定是局域网,但总体位于公司防火墙之内,环境可控。 本文可能不适合: PC 客户端网络编程,程序运行在客户的PC 上,环境多变且不可控。 Windows 网络编程。 面向公网的服务程序。 高性能网络服务器。 本文分两个部分: 1.网络编程的一些“胡思乱想”,以自问自答的形式谈谈我对这一领域的认识。 2.几本必看的书,基本上还是W.Richard Stevents 的那几本。 另外,本文没有特别说明时均暗指TCP 协议,“连接”是“TCP 连接”,“服务端”是“TCP 服务端”。 A.1 网络编程的一些“胡思乱想” 以下大致列出我对网络编程的一些想法,前后无关联。 A.1.1 网络编程是什么 网络编程是什么?是熟练使用Sockets API吗?说实话,在实际项目里我只用过两次Sockets API,其他时候都是使用封装好的网络库。 第一次是2005年在学校做一个羽毛球赛场计分系统:我用C#编写运行在PC上的软件,负责比分的显示;再用C#写了运行在PDA上的计分界面,记分员拿着PDA记录比分;这两部分程序通过TCP协议相互通信。这其实是个简单的分布式系统,体育馆有几片场地,每个场地都有一名拿PDA的记分员,每个场地都有两台显示比分的PC(显示器是42寸平板电视,放在场地的对角,这样两边看台的观众都能看到比分)。这两台PC的功能不完全一样,一台只负责显示当前比分,另一台还要负责与PDA通信,并更新数据库里的比分信息。此外,还有一台PC负责周期性地从数据库读出全部7片场地的比分,显示在体育馆墙上的大屏幕上。这台PC上还运行着一个程序,负责生成比分数据的静态页面,通过FTP上传发布到某门户网站的体育频道。系统中还有一个录入赛程(参赛队、运动员、出场顺序等)数据库的程序,运行在数据库服务器上。算下来整个系统有十来个程序,运行在二十多台设备(PC 和PDA)上,还要考虑可靠性,避免single point of failure。 这是我第一次写实际项目中的网络程序,当时写下来的感觉是像写命令行与用户交互的程序:程序在命令行输出一句提示语,等待客户输入一句话,然后处理客户输入,再输出下一句提示语,如此循环。只不过这里的“客户”不是人,而是另一个程序。在建立好TCP 连接之后,双方的程序都是read/write 循环(为求简单,我用的是blocking 读写),直到有一方断开连接。 第二次是2010 年编写muduo 网络库,我再次拿起了Sockets API,写了一个基于Reactor 模式的C++ 网络库。写这个库的目的之一就是想让日常的网络编程从Sockets API 的琐碎细节中解脱出来,让程序员专注于业务逻辑,把时间用在刀刃上。muduo 网络库的示例代码包含了几十个网络程序,这些示例程序都没有直接使用Sockets API。 在此之外,无论是实习还是工作,虽然我写的程序都会通过TCP 协议与其他程序打交道,但我没有直接使用过Sockets API。对于TCP 网络编程,我认为核心是处理“三个半事件”,见§6.4.1“TCP 网络编程本质论”。程序员的主要工作是在事件处理函数中实现业务逻辑,而不是和Sockets API“较劲”。 这里还是没有说清楚“网络编程”是什么,请继续阅读后文§A.1.5“网络编程的各种任务角色”。 A.1.2 学习网络编程有用吗 以上说的是比较底层的网络编程,程序代码直接面对从TCP 或UDP 收到的数据以及构造数据包发出去。在实际工作中,另一种常见的情况是通过各种client library来与服务端打交道,或者在现成的框架中填空来实现server,或者采用更上层的通信方式。比如用libmemcached 与memcached 打交道,使用libpq 来与PostgreSQL 打交道,编写Servlet 来响应HTTP 请求,使用某种RPC 与其他进程通信,等等。这些情况都会发生网络通信,但不一定算作“网络编程”。如果你的工作是前面列举的这些,学习TCP/IP 网络编程还有用吗? 我认为还是有必要学一学,至少在troubleshooting 的时候有用。无论如何,这些library 或framework 都会调用底层的Sockets API 来实现网络功能。当你的程序遇到一个线上问题时,如果你熟悉Sockets API,那么从strace 不难发现程序卡在哪里,尽管可能你没有直接调用这些Sockets API。另外,熟悉TCP/IP 协议、会用tcpdump 也非常有助于分析解决线上网络服务问题。 A.1.3 在什么平台上学习网络编程 对于服务端网络编程,我建议在Linux 上学习。 如果在10年前,这个问题的答案或许是FreeBSD,因为FreeBSD“根正苗红”,在2000年那一次互联网浪潮中扮演了重要角色,是很多公司首选的免费服务器操作系统。2000 年那会儿Linux 还远未成熟,连epoll 都还没有实现。(FreeBSD 在2001年发布4.1 版,加入了kqueue,从此C10k 不是问题。) 10年后的今天,事情起了一些变化,Linux成为市场份额最大的服务器操作系统。在Linux这种大众系统上学网络编程,遇到什么问题会比较容易解决。因为用的人多,你遇到的问题别人多半也遇到过;同样因为用的人多,如果真的有什么内核bug,很快就会得到修复,至少有work around 的办法。如果用别的系统,可能一个问题发到论坛上半个月都不会有人理。从内核源码的风格看,FreeBSD 更干净整洁,注释到位,但是无奈它的市场份额远不如Linux,学习Linux 是更好的技术投资。 A.1.4 可移植性重要吗 写网络程序要不要考虑移植性?要不要跨平台?这取决于项目需要,如果贵公司做的程序要卖给其他公司,而对方可能使用Windows、Linux、FreeBSD、Solaris、AIX、HP-UX 等等操作系统,这时候当然要考虑移植性。如果编写公司内部的服务器上用的网络程序,那么大可只关注一个平台,比如Linux。因为编写和维护可移植的网络程序的代价相当高,平台间的差异可能远比想象中大,即便是POSIX 系统之间也有不小的差异(比如Linux 没有SO_NOSIGPIPE 选项,Linux 的pipe(2) 是单向的,而FreeBSD 是双向的),错误的返回码也大不一样。 我就不打算把muduo 往Windows 或其他操作系统移植。如果需要编写可移植的网络程序,我宁愿用libevent、libuv、Java Netty 这样现成的库,把“脏活、累活”留给别人。 A.1.5 网络编程的各种任务角色 计算机网络是个big topic,涉及很多人物和角色,既有开发人员,也有运维人员。比方说:公司内部两台机器之间ping 不通,通常由网络运维人员解决,看看是布线有问题还是路由器设置不对;两台机器能ping 通,但是程序连不上,经检查是本机防火墙设置有问题,通常由系统管理员解决;两台机器能连上,但是丢包很严重,发现是网卡或者交换机的网口故障,由硬件维修人员解决;两台机器的程序能连上,但是偶尔发过去的请求得不到响应,通常是程序bug,应该由开发人员解决。 本文主要关心开发人员这一角色。下面简单列出一些我能想到的跟网络打交道的编程任务,其中前三项是面向网络本身,后面几项是在计算机网络之上构建信息系统。 1.开发网络设备,编写防火墙、交换机、路由器的固件(firmware)。 2.开发或移植网卡的驱动。 3.移植或维护TCP/IP 协议栈(特别是在嵌入式系统上)。 4.开发或维护标准的网络协议程序,HTTP、FTP、DNS、SMTP、POP3、NFS。 5.开发标准网络协议的“附加品”,比如HAProxy、squid、varnish 等Web loadbalancer。 6.开发标准或非标准网络服务的客户端库,比如ZooKeeper 客户端库、memcached客户端库。 7.开发与公司业务直接相关的网络服务程序,比如即时聊天软件的后台服务器、网游服务器、金融交易系统、互联网企业用的分布式海量存储、微博发帖的内部广播通知等等。 8.客户端程序中涉及网络的部分,比如邮件客户端中与POP3、SMTP 通信的部分,以及网游的客户端程序中与服务器通信的部分。 本文所指的“网络编程”专指第7 项,即在TCP/IP 协议之上开发业务软件。换句话说,不是用Sockets API 开发muduo 这样的网络库,而是用libevent、muduo、Netty、gevent 这样现成的库开发业务软件,muduo 自带的十几个示例程序是业务软件的代表。 A.1.6 面向业务的网络编程的特点 与通用的网络服务器不同,面向公司业务的专用网络程序有其自身的特点。 业务逻辑比较复杂,而且时常变化 如果写一个HTTP 服务器,在大致实现HTTP 1.1 标准之后,程序的主体功能一般不会有太大的变化,程序员会把时间放在性能调优和bug 修复上。而开发针对公司业务的专用程序时,功能说明书(spec)很可能不如HTTP 1.1 标准那么细致明确。更重要的是,程序是快速演化的。以即时聊天工具的后台服务器为例,可能第一版只支持在线聊天;几个月之后发布第二版,支持离线消息;又过了几个月,第三版支持隐身聊天;随后,第四版支持上传头像;如此等等。这要求程序员能快速响应新的业务需求,公司才能保持竞争力。由于业务时常变化(假设每月一次版本升级),也会降低服务程序连续运行时间的要求。相反,我们要设计一套流程,通过轮流重启服务器来完成平滑升级(§9.2.2)。 不一定需要遵循公认的通信协议标准 比方说网游服务器就没什么协议标准,反正客户端和服务端都是本公司开发的,如果发现目前的协议设计有问题,两边一起改就行了。由于可以自己设计协议,因此我们可以绕开一些性能难点,简化程序结构。比方说,对于多线程的服务程序,如果用短连接TCP 协议,为了优化性能通常要精心设计accept 新连接的机制2,避免惊群并减少上下文切换。但是如果改用长连接,用最简单的单线程accept 就行了。 程序结构没有定论 对于高并发大吞吐的标准网络服务,一般采用单线程事件驱动的方式开发,比如HAProxy、lighttpd 等都是这个模式。但是对于专用的业务系统,其业务逻辑比较复杂,占用较多的CPU 资源,这种单线程事件驱动方式不见得能发挥现在多核处理器的优势。这留给程序员比较大的自由发挥空间,做好了“横扫千军”,做烂了一败涂地。我认为目前one loop per thread 是通用性较高的一种程序结构,能发挥多核的优势,见§3.3 和§6.6。 性能评判的标准不同 如果开发httpd 这样的通用服务,必然会和开源的Nginx、lighttpd 等高性能服务器比较,程序员要投入相当的精力去优化程序,才能在市场上占有一席之地。而面向业务的专用网络程序不一定是IO bound,也不一定有开源的实现以供对比性能,优化方向也可能不同。程序员通常更加注重功能的稳定性与开发的便捷性。性能只要一代比一代强即可。 网络编程起到支撑作用,但不处于主导地位 程序员的主要工作是实现业务逻辑,而不只是实现网络通信协议。这要求程序员深入理解业务。程序的性能瓶颈不一定在网络上,瓶颈有可能是CPU、Disk IO、数据库等,这时优化网络方面的代码并不能提高整体性能。只有对所在的领域有深入的了解,明白各种因素的权衡(trade-off),才能做出一些有针对性的优化。现在的机器上,简单的并发长连接echo服务程序不用特别优化就做到十多万qps,但是如果每个业务请求需要1ms 密集计算,在8 核机器上充其量能达到8000 qps,优化IO 不如去优化业务计算(如果投入产出合算的话)。 A.1.7 几个术语 互联网上的很多“口水战”是由对同一术语的不同理解引起的,比如我写的《多线程服务器的适用场合》3,就曾经被人说是“挂羊头卖狗肉”,因为这篇文章中举的master 例子“根本就算不上是个网络服务器。因为它的瓶颈根本就跟网络无关。” 网络服务器 “网络服务器”这个术语确实含义模糊,到底指硬件还是软件?到底是服务于网络本身的机器(交换机、路由器、防火墙、NAT),还是利用网络为其他人或程序提供服务的机器(打印服务器、文件服务器、邮件服务器)?每个人根据自己熟悉的领域,可能会有不同的解读。比方说,或许有人认为只有支持高并发、高吞吐量的才算是网络服务器。 为了避免无谓的争执,我只用“网络服务程序”或者“网络应用程序”这种含义明确的术语。“开发网络服务程序”通常不会造成误解。 客户端?服务端?在TCP 网络编程中,客户端和服务端很容易区分,主动发起连接的是客户端,被动接受连接的是服务端。当然,这个“客户端”本身也可能是个后台服务程序,HTTP proxy 对HTTP server 来说就是个客户端。 客户端编程?服务端编程?但是“服务端编程”和“客户端编程”就不那么好区分了。比如Web crawler,它会主动发起大量连接,扮演的是HTTP客户端的角色,但似乎应该归入“服务端编程”。又比如写一个HTTP proxy,它既会扮演服务端——被动接受Web browser 发起的连接,也会扮演客户端——主动向HTTP server发起连接,它究竟算服务端还是客户端?我猜大多数人会把它归入服务端编程。 那么究竟如何定义“服务端编程”? 服务端编程需要处理大量并发连接?也许是,也许不是。比如云风在一篇介绍网游服务器的博客4中就谈到,网游中用到的“连接服务器”需要处理大量连接,而“逻辑服务器”只有一个外部连接。那么开发这种网游“逻辑服务器”算服务端编程还是客户端编程呢?又比如机房的服务进程监控软件,并发数跟机器数成正比,至多也就是两三千的并发连接。(再大规模就超出本书的范围了。) 我认为,“服务端网络编程”指的是编写没有用户界面的长期运行的网络程序,程序默默地运行在一台服务器上,通过网络与其他程序打交道,而不必和人打交道。与之对应的是客户端网络程序,要么是短时间运行,比如wget;要么是有用户界面(无论是字符界面还是图形界面)。本文主要谈服务端网络编程。

前言

本书主要讲述采用现代C++ 在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,这也是我对过去5年编写生产环境下的多线程服务端程序的经验总结。本书重点讲解多线程网络服务器的一种IO 模型,即one loop per thread。这是一种适应性较强的模型,也是Linux 下以native语言编写用户态高性能网络程序最成熟的模式,掌握之后可顺利地开发各类常见的服务端网络应用程序。本书以muduo网络库为例,讲解这种编程模型的使用方法及注意事项。muduo 是一个基于非阻塞IO 和事件驱动的现代C++ 网络库,原生支持oneloop per thread 这种IO 模型。muduo 适合开发Linux 下的面向业务的多线程服务端网络应用程序,其中“面向业务的网络编程”的定义见附录A。“现代C++”指的不是C++11 新标准,而是2005 年TR1 发布之后的C++ 语言和库。与传统C++ 相比,现代C++ 的变化主要有两方面:资源管理(见第1 章)与事件回调(见第449 页)。本书不是多线程编程教程,也不是网络编程教程,更不是C++教程。读者应该已经大致读过《UNIX环境高级编程》、《UNIX网络编程》、《C++Primer》或与之内容相近的书籍。本书不谈C++11,因为目前(2012年)主流的Linux 服务端发行版的g++版本都还停留在4.4,C++11 进入实用尚需一段时日。本书适用的硬件环境是主流x86-64 服务器,多路多核CPU、几十GB 内存、千兆以太网互联。除了第5章讲诊断日志之外,本书不涉及文件IO。本书分为四大部分,第1 部分“C++ 多线程系统编程”考察多线程下的对象生命期管理、线程同步方法、多线程与C++ 的结合、高效的多线程日志等。第2 部分“muduo 网络库”介绍使用现成的非阻塞网络库编写网络应用程序的方法,以及muduo的设计与实现。第3部分“工程实践经验谈”介绍分布式系统的工程化开发方法和C++在工程实践中的功能特性取舍。第4部分“附录”分享网络编程和C++语言的学习经验。本书的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步的功能需求,还能写出更易用的同步设施。掌握一种进程间通信方式和一种多线程网络编程模型就足以应对日常开发任务,编写运行于公司内网环境的分布式服务系统。(本书不涉及分布式存储系统,也不涉及UDP。)术语与排版范例本书大量使用英文术语,甚至有少量英文引文。设计模式的名字一律用英文,例如Observer、Reactor、Singleton。在中文术语不够突出时,也会使用英文,例如class、heap、event loop、STLalgorithm等。注意几个中文C++术语:对象实体(instance)、函数重载决议(resolution)、模板具现化(instantiation)、覆写(override)虚函数、提领(dereference)指针。本书中的英语可数名词一般不用复数形式,例如两个class,6 个syscall;但有时会用(s) 强调中文名词是复数。fd 是文件描述符(file descriptor)的缩写。“CPU数目”一般指的是核(core)的数目。容量单位kB、MB、GB表示的字节数分别为103、106、109,在特别强调准确数值时,会分别用KiB、MiB、GiB 表示210、220、230 字节。用诸如§11.5 表示本书第11.5 节,L42 表示上下文中出现的第42 行代码。[JCP]、[CC2e] 等是参考文献,见书末清单。

内容概要

陈硕,北京师范大学硕士,擅长C++ 多线程网络编程和实时分布式系统架构。曾在摩根士丹利IT 部门工作5 年,从事实时外汇交易系统开发。现在在美国加州硅谷某互联网大公司工作,从事大规模分布式系统的可靠性工程。编写了开源C++ 网络库muduo,参与翻译了《代码大全( 第2 版)》和《C++ 编程规范(繁体版)》,整理了《C++ Primer (第4 版)(评注版)》,并曾多次在各地技术大会演讲。

书籍目录

第1 部分C++ 多线程系统编程1
第1章 线程安全的对象生命期管理3
1.1 当析构函数遇到多线程. . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.1 线程安全的定义. . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 MutexLock 与MutexLockGuard . . . . . . . . . . . . . . . . . . . . 4
1.1.3 一个线程安全的Counter 示例. . . . . . . . . . . . . . . . . . . . 4
1.2 对象的创建很简单. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 销毁太难. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3.1 mutex 不是办法. . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3.2 作为数据成员的mutex 不能保护析构. . . . . . . . . . . . . . . 8
1.4 线程安全的Observer 有多难. . . . . . . . . . . . . . . . . . . . . . . . . 8
1.5 原始指针有何不妥. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.6 神器shared_ptr/weak_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.7 插曲:系统地避免各种指针错误. . . . . . . . . . . . . . . . . . . . . . . 14
1.8 应用到Observer 上. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.9 再论shared_ptr 的线程安全. . . . . . . . . . . . . . . . . . . . . . . . . 17
1.10 shared_ptr 技术与陷阱. . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.11 对象池. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.11.1 enable_shared_from_this . . . . . . . . . . . . . . . . . . . . . . 23
1.11.2 弱回调. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.12 替代方案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.13 心得与小结. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.14 Observer 之谬. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
第2章 线程同步精要31
2.1 互斥器(mutex) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.1.1 只使用非递归的mutex . . . . . . . . . . . . . . . . . . . . . . . . 33
2.1.2 死锁. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.2 条件变量(condition variable) . . . . . . . . . . . . . . . . . . . . . . . 40
2.3 不要用读写锁和信号量. . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.4 封装MutexLock、MutexLockGuard、Condition . . . . . . . . . . . . . . 44
2.5 线程安全的Singleton 实现. . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.6 sleep(3) 不是同步原语. . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.7 归纳与总结. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.8 借shared_ptr 实现copy-on-write . . . . . . . . . . . . . . . . . . . . . . 52
第3章 多线程服务器的适用场合与常用编程模型59
3.1 进程与线程. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.2 单线程服务器的常用编程模型. . . . . . . . . . . . . . . . . . . . . . . . 61
3.3 多线程服务器的常用编程模型. . . . . . . . . . . . . . . . . . . . . . . . 62
3.3.1 one loop per thread . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.3.2 线程池. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.3.3 推荐模式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.4 进程间通信只用TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.5 多线程服务器的适用场合. . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.5.1 必须用单线程的场合. . . . . . . . . . . . . . . . . . . . . . . . . 69
3.5.2 单线程程序的优缺点. . . . . . . . . . . . . . . . . . . . . . . . . 70
3.5.3 适用多线程程序的场景. . . . . . . . . . . . . . . . . . . . . . . . 71
3.6 “多线程服务器的适用场合”例释与答疑. . . . . . . . . . . . . . . . . . 74
第4章 C++ 多线程系统编程精要83
4.1 基本线程原语的选用. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
4.2 C/C++ 系统库的线程安全性. . . . . . . . . . . . . . . . . . . . . . . . . 85
4.3 Linux 上的线程标识. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.4 线程的创建与销毁的守则. . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.4.1 pthread_cancel 与C++ . . . . . . . . . . . . . . . . . . . . . . . 94
4.4.2 exit(3) 在C++ 中不是线程安全的. . . . . . . . . . . . . . . . . 94
4.5 善用__thread 关键字. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.6 多线程与IO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
4.7 用RAII 包装文件描述符. . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.8 RAII 与fork() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
4.9 多线程与fork() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
4.10 多线程与signal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.11 Linux 新增系统调用的启示. . . . . . . . . . . . . . . . . . . . . . . . . . 105
第5章 高效的多线程日志107
5.1 功能需求. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
5.2 性能需求. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
5.3 多线程异步日志. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
5.4 其他方案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
第2部分 muduo 网络库123
第6章 muduo 网络库简介125
6.1 由来. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
6.2 安装. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
6.3 目录结构. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
6.3.1 代码结构. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
6.3.2 例子. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
6.3.3 线程模型. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
6.4 使用教程. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
6.4.1 TCP 网络编程本质论. . . . . . . . . . . . . . . . . . . . . . . . . 136
6.4.2 echo 服务的实现. . . . . . . . . . . . . . . . . . . . . . . . . . . 138
6.4.3 七步实现finger 服务. . . . . . . . . . . . . . . . . . . . . . . . . 140
6.5 性能评测. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
6.5.1 muduo 与Boost.Asio、libevent2 的吞吐量对比. . . . . . . . . . 145
6.5.2 击鼓传花:对比muduo 与libevent2 的事件处理效率. . . . . . 148
6.5.3 muduo 与Nginx 的吞吐量对比. . . . . . . . . . . . . . . . . . . 153
6.5.4 muduo 与ZeroMQ 的延迟对比. . . . . . . . . . . . . . . . . . . 156
6.6 详解muduo 多线程模型. . . . . . . . . . . . . . . . . . . . . . . . . . . 157
6.6.1 数独求解服务器. . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
6.6.2 常见的并发网络服务程序设计方案. . . . . . . . . . . . . . . . . 160
第7章 muduo 编程示例177
7.1 五个简单TCP 示例. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
7.2 文件传输. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
7.3 Boost.Asio 的聊天服务器. . . . . . . . . . . . . . . . . . . . . . . . . . . 194
7.3.1 TCP 分包. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
7.3.2 消息格式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
7.3.3 编解码器LengthHeaderCodec . . . . . . . . . . . . . . . . . . . . 197
7.3.4 服务端的实现. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
7.3.5 客户端的实现. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
7.4 muduo Buffer 类的设计与使用. . . . . . . . . . . . . . . . . . . . . . . 204
7.4.1 muduo 的IO 模型. . . . . . . . . . . . . . . . . . . . . . . . . . 204
7.4.2 为什么non-blocking 网络编程中应用层buffer 是必需的. . . . 205
7.4.3 Buffer 的功能需求. . . . . . . . . . . . . . . . . . . . . . . . . . 207
7.4.4 Buffer 的数据结构. . . . . . . . . . . . . . . . . . . . . . . . . . 209
7.4.5 Buffer 的操作. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
7.4.6 其他设计方案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
7.4.7 性能是不是问题. . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
7.5 一种自动反射消息类型的Google Protobuf 网络传输方案. . . . . . . . 220
7.5.1 网络编程中使用Protobuf 的两个先决条件. . . . . . . . . . . . . 220
7.5.2 根据type name 反射自动创建Message 对象. . . . . . . . . . . . 221
7.5.3 Protobuf 传输格式. . . . . . . . . . . . . . . . . . . . . . . . . . 226
7.6 在muduo 中实现Protobuf 编解码器与消息分发器. . . . . . . . . . . . 228
7.6.1 什么是编解码器(codec) . . . . . . . . . . . . . . . . . . . . . . 229
7.6.2 实现ProtobufCodec . . . . . . . . . . . . . . . . . . . . . . . . . 232
7.6.3 消息分发器(dispatcher)有什么用. . . . . . . . . . . . . . . . 232
7.6.4 ProtobufCodec 与ProtobufDispatcher 的综合运用. . . . . . . 233
7.6.5 ProtobufDispatcher 的两种实现. . . . . . . . . . . . . . . . . . 234
7.6.6 ProtobufCodec 和ProtobufDispatcher 有何意义. . . . . . . . . 236
7.7 限制服务器的最大并发连接数. . . . . . . . . . . . . . . . . . . . . . . . 237
7.7.1 为什么要限制并发连接数. . . . . . . . . . . . . . . . . . . . . . 237
7.7.2 在muduo 中限制并发连接数. . . . . . . . . . . . . . . . . . . . 238
7.8 定时器. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
7.8.1 程序中的时间. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
7.8.2 Linux 时间函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
7.8.3 muduo 的定时器接口. . . . . . . . . . . . . . . . . . . . . . . . . 242
7.8.4 Boost.Asio Timer 示例. . . . . . . . . . . . . . . . . . . . . . . . 243
7.8.5 Java Netty 示例. . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
7.9 测量两台机器的网络延迟和时间差. . . . . . . . . . . . . . . . . . . . . 248
7.10 用timing wheel 踢掉空闲连接. . . . . . . . . . . . . . . . . . . . . . . . 250
7.10.1 timing wheel 原理. . . . . . . . . . . . . . . . . . . . . . . . . . 251
7.10.2 代码实现与改进. . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
7.11 简单的消息广播服务. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
7.12 “串并转换”连接服务器及其自动化测试. . . . . . . . . . . . . . . . . . 260
7.13 socks4a 代理服务器. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
7.13.1 TCP 中继器. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
7.13.2 socks4a 代理服务器. . . . . . . . . . . . . . . . . . . . . . . . . . 267
7.13.3 N : 1 与1 : N 连接转发. . . . . . . . . . . . . . . . . . . . . . . . 267
7.14 短址服务. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
7.15 与其他库集成. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
7.15.1 UDNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
7.15.2 c-ares DNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
7.15.3 curl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
7.15.4 更多. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
第8章 muduo 网络库设计与实现277
8.0 什么都不做的EventLoop . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
8.1 Reactor 的关键结构. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
8.1.1 Channel class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
8.1.2 Poller class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
8.1.3 EventLoop 的改动. . . . . . . . . . . . . . . . . . . . . . . . . . . 287
8.2 TimerQueue 定时器. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
8.2.1 TimerQueue class . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
8.2.2 EventLoop 的改动. . . . . . . . . . . . . . . . . . . . . . . . . . . 292
8.3 EventLoop::runInLoop() 函数. . . . . . . . . . . . . . . . . . . . . . . . 293
8.3.1 提高TimerQueue 的线程安全性. . . . . . . . . . . . . . . . . . . 296
8.3.2 EventLoopThread class . . . . . . . . . . . . . . . . . . . . . . . . 297
8.4 实现TCP 网络库. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
8.5 TcpServer 接受新连接. . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
8.5.1 TcpServer class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
8.5.2 TcpConnection class . . . . . . . . . . . . . . . . . . . . . . . . . 305
8.6 TcpConnection 断开连接. . . . . . . . . . . . . . . . . . . . . . . . . . . 308
8.7 Buffer 读取数据. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
8.7.1 TcpConnection 使用Buffer 作为输入缓冲. . . . . . . . . . . . . 314
8.7.2 Buffer::readFd() . . . . . . . . . . . . . . . . . . . . . . . . . . 315
8.8 TcpConnection 发送数据. . . . . . . . . . . . . . . . . . . . . . . . . . . 316
8.9 完善TcpConnection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
8.9.1 SIGPIPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
8.9.2 TCP No Delay 和TCP keepalive . . . . . . . . . . . . . . . . . . 321
8.9.3 WriteCompleteCallback 和HighWaterMarkCallback . . . . . . . 322
8.10 多线程TcpServer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
8.11 Connector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
8.12 TcpClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
8.13 epoll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
8.14 测试程序一览. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
第3部分 工程实践经验谈337
第9章 分布式系统工程实践339
9.1 我们在技术浪潮中的位置. . . . . . . . . . . . . . . . . . . . . . . . . . . 341
9.1.1 分布式系统的本质困难. . . . . . . . . . . . . . . . . . . . . . . . 343
9.1.2 分布式系统是个险恶的问题. . . . . . . . . . . . . . . . . . . . . 344
9.2 分布式系统的可靠性浅说. . . . . . . . . . . . . . . . . . . . . . . . . . . 349
9.2.1 分布式系统的软件不要求7 24 可靠. . . . . . . . . . . . . . . . 352
9.2.2 “能随时重启进程”作为程序设计目标. . . . . . . . . . . . . . . 354
9.3 分布式系统中心跳协议的设计. . . . . . . . . . . . . . . . . . . . . . . . 356
9.4 分布式系统中的进程标识. . . . . . . . . . . . . . . . . . . . . . . . . . . 360
9.4.1 错误做法. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
9.4.2 正确做法. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
9.4.3 TCP 协议的启示. . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
9.5 构建易于维护的分布式程序. . . . . . . . . . . . . . . . . . . . . . . . . 364
9.6 为系统演化做准备. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
9.6.1 可扩展的消息格式. . . . . . . . . . . . . . . . . . . . . . . . . . 368
9.6.2 反面教材:ICE 的消息打包格式. . . . . . . . . . . . . . . . . . . 369
9.7 分布式程序的自动化回归测试. . . . . . . . . . . . . . . . . . . . . . . . 370
9.7.1 单元测试的能与不能. . . . . . . . . . . . . . . . . . . . . . . . . 370
9.7.2 分布式系统测试的要点. . . . . . . . . . . . . . . . . . . . . . . . 373
9.7.3 分布式系统的抽象观点. . . . . . . . . . . . . . . . . . . . . . . . 374
9.7.4 一种自动化的回归测试方案. . . . . . . . . . . . . . . . . . . . . 375
9.7.5 其他用处. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
9.8 分布式系统部署、监控与进程管理的几重境界. . . . . . . . . . . . . . . 380
9.8.1 境界1:全手工操作. . . . . . . . . . . . . . . . . . . . . . . . . 382
9.8.2 境界2:使用零散的自动化脚本和第三方组件. . . . . . . . . . . 383
9.8.3 境界3:自制机群管理系统,集中化配置. . . . . . . . . . . . . 386
9.8.4 境界4:机群管理与naming service 结合. . . . . . . . . . . . . 389
第10章 C++ 编译链接模型精要391
10.1 C 语言的编译模型及其成因. . . . . . . . . . . . . . . . . . . . . . . . . 394
10.1.1 为什么C 语言需要预处理. . . . . . . . . . . . . . . . . . . . . . 395
10.1.2 C 语言的编译模型. . . . . . . . . . . . . . . . . . . . . . . . . . . 398
10.2 C++ 的编译模型. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
10.2.1 单遍编译. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
10.2.2 前向声明. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
10.3 C++ 链接(linking) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
10.3.1 函数重载. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
10.3.2 inline 函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
10.3.3 模板. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
10.3.4 虚函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
10.4 工程项目中头文件的使用规则. . . . . . . . . . . . . . . . . . . . . . . . 415
10.4.1 头文件的害处. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
10.4.2 头文件的使用规则. . . . . . . . . . . . . . . . . . . . . . . . . . 417
10.5 工程项目中库文件的组织原则. . . . . . . . . . . . . . . . . . . . . . . . 418
10.5.1 动态库是有害的. . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
10.5.2 静态库也好不到哪儿去. . . . . . . . . . . . . . . . . . . . . . . . 424
10.5.3 源码编译是王道. . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
第11章 反思C++ 面向对象与虚函数429
11.1 朴实的C++ 设计. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
11.2 程序库的二进制兼容性. . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
11.2.1 什么是二进制兼容性. . . . . . . . . . . . . . . . . . . . . . . . . 432
11.2.2 有哪些情况会破坏库的ABI . . . . . . . . . . . . . . . . . . . . . 433
11.2.3 哪些做法多半是安全的. . . . . . . . . . . . . . . . . . . . . . . . 435
11.2.4 反面教材:COM . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
11.2.5 解决办法. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
11.3 避免使用虚函数作为库的接口. . . . . . . . . . . . . . . . . . . . . . . . 436
11.3.1 C++ 程序库的作者的生存环境. . . . . . . . . . . . . . . . . . . . 437
11.3.2 虚函数作为库的接口的两大用途. . . . . . . . . . . . . . . . . . 438
11.3.3 虚函数作为接口的弊端. . . . . . . . . . . . . . . . . . . . . . . . 439
11.3.4 假如Linux 系统调用以COM 接口方式实现. . . . . . . . . . . . 442
11.3.5 Java 是如何应对的. . . . . . . . . . . . . . . . . . . . . . . . . . 443
11.4 动态库接口的推荐做法. . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
11.5 以boost::function 和boost::bind 取代虚函数. . . . . . . . . . . . . 447
11.5.1 基本用途. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
11.5.2 对程序库的影响. . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
11.5.3 对面向对象程序设计的影响. . . . . . . . . . . . . . . . . . . . . 453
11.6 iostream 的用途与局限. . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
11.6.1 stdio 格式化输入输出的缺点. . . . . . . . . . . . . . . . . . . . . 457
11.6.2 iostream 的设计初衷. . . . . . . . . . . . . . . . . . . . . . . . . 461
11.6.3 iostream 与标准库其他组件的交互. . . . . . . . . . . . . . . . . 463
11.6.4 iostream 在使用方面的缺点. . . . . . . . . . . . . . . . . . . . . 464
11.6.5 iostream 在设计方面的缺点. . . . . . . . . . . . . . . . . . . . . 468
11.6.6 一个300 行的memory buffer output stream . . . . . . . . . . . 476
11.6.7 现实的C++ 程序如何做文件IO . . . . . . . . . . . . . . . . . . . 480
11.7 值语义与数据抽象. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
11.7.1 什么是值语义. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
11.7.2 值语义与生命期. . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
11.7.3 值语义与标准库. . . . . . . . . . . . . . . . . . . . . . . . . . . . 488
11.7.4 值语义与C++ 语言. . . . . . . . . . . . . . . . . . . . . . . . . . 488
11.7.5 什么是数据抽象. . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
11.7.6 数据抽象所需的语言设施. . . . . . . . . . . . . . . . . . . . . . 493
11.7.7 数据抽象的例子. . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
第12章 C++ 经验谈501
12.1 用异或来交换变量是错误的. . . . . . . . . . . . . . . . . . . . . . . . . 501
12.1.1 编译器会分别生成什么代码. . . . . . . . . . . . . . . . . . . . . 503
12.1.2 为什么短的代码不一定快. . . . . . . . . . . . . . . . . . . . . . 505
12.2 不要重载全局::operator new() . . . . . . . . . . . . . . . . . . . . . . 507
12.2.1 内存管理的基本要求. . . . . . . . . . . . . . . . . . . . . . . . . 507
12.2.2 重载::operator new() 的理由. . . . . . . . . . . . . . . . . . . 508
12.2.3 ::operator new() 的两种重载方式. . . . . . . . . . . . . . . . . 508
12.2.4 现实的开发环境. . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
12.2.5 重载::operator new() 的困境. . . . . . . . . . . . . . . . . . . 510
12.2.6 解决办法:替换malloc() . . . . . . . . . . . . . . . . . . . . . . 512
12.2.7 为单独的class 重载::operator new() 有问题吗. . . . . . . . . 513
12.2.8 有必要自行定制内存分配器吗. . . . . . . . . . . . . . . . . . . . 513
12.3 带符号整数的除法与余数. . . . . . . . . . . . . . . . . . . . . . . . . . . 514
12.3.1 语言标准怎么说. . . . . . . . . . . . . . . . . . . . . . . . . . . . 515
12.3.2 C/C++ 编译器的表现. . . . . . . . . . . . . . . . . . . . . . . . . 516
12.3.3 其他语言的规定. . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
12.3.4 脚本语言解释器代码. . . . . . . . . . . . . . . . . . . . . . . . . 517
12.3.5 硬件实现. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521
12.4 在单元测试中mock 系统调用. . . . . . . . . . . . . . . . . . . . . . . . 522
12.4.1 系统函数的依赖注入. . . . . . . . . . . . . . . . . . . . . . . . . 522
12.4.2 链接期垫片(link seam) . . . . . . . . . . . . . . . . . . . . . . 524
12.5 慎用匿名namespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526
12.5.1 C 语言的static 关键字的两种用法. . . . . . . . . . . . . . . . . 526
12.5.2 C++ 语言的static 关键字的四种用法. . . . . . . . . . . . . . . . 526
12.5.3 匿名namespace 的不利之处. . . . . . . . . . . . . . . . . . . . . 527
12.5.4 替代办法. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
12.6 采用有利于版本管理的代码格式. . . . . . . . . . . . . . . . . . . . . . . 529
12.6.1 对diff 友好的代码格式. . . . . . . . . . . . . . . . . . . . . . . . 530
12.6.2 对grep 友好的代码风格. . . . . . . . . . . . . . . . . . . . . . . 537
12.6.3 一切为了效率. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538
12.7 再探std::string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
12.7.1 直接拷贝(eager copy) . . . . . . . . . . . . . . . . . . . . . . . 540
12.7.2 写时复制(copy-on-write) . . . . . . . . . . . . . . . . . . . . . 542
12.7.3 短字符串优化(SSO) . . . . . . . . . . . . . . . . . . . . . . . . 543
12.8 用STL algorithm 轻松解决几道算法面试题. . . . . . . . . . . . . . . . 546
12.8.1 用next_permutation() 生成排列与组合. . . . . . . . . . . . . . 546
12.8.2 用unique() 去除连续重复空白. . . . . . . . . . . . . . . . . . . 548
12.8.3 用{make,push,pop}_heap() 实现多路归并. . . . . . . . . . . . 549
12.8.4 用partition() 实现“重排数组,让奇数位于偶数前面” . . . . 553
12.8.5 用lower_bound() 查找IP 地址所属的城市. . . . . . . . . . . . . 554
第4 部分附录559
附录A 谈一谈网络编程学习经验561
附录B 从《C++ Primer(第4 版)》入手学习C++ 579
附录C 关于Boost 的看法591
附录D 关于TCP 并发连接的几个思考题与试验593
参考文献599

编辑推荐

《Linux多线程服务端编程:使用muduo C++网络库》编辑推荐:示范在多核时代采用现代C++编写,多线程TCP网络服务器的正规做法。

作者简介

本书主要讲述采用现代C++ 在x86-64 Linux 上编写多线程TCP 网络服务程序的
主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop
per thread。这是在Linux 下以native 语言编写用户态高性能网络程序最成熟的模
式,掌握之后可顺利地开发各类常见的服务端网络应用程序。本书以muduo 网络库
为例,讲解这种编程模型的使用方法及注意事项。
本书的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步
的功能需求,还能写出更易用的同步设施。掌握一种进程间通信方式和一种多线程网
络编程模型就足以应对日常开发任务,编写运行于公司内网环境的分布式服务系统。

图书封面


 Linux多线程服务端编程下载 精选章节试读 更多精彩书评



发布书评

 
 


精彩书评 (总计12条)

  •     9.1分,尼玛,坑谁呢。。。。。看这里,比较客观http://ar.newsmth.net/thread-c64b61785ba061.htmlmuduo适用于什么环境? muduo的官方一句话自我介绍是:A C++ non-blocking multi-threaded network library for Linux。 在其readme和wiki中均未提及此lib是否适用于实际场景,于是我花了些时间翻看了一 下,得出的结论是此lib仅限于展示epoll/poll的基本用法,对网络编程初学者是否有参考 价值还有待进一步考察。 任何一个网络产品除了要支持网络event之外,还必须处理另外两种事件:signal和 timer。 muduo也毫无例外。但近看一下就发现muduo对single和timer的支持很有喜感。 除了SIGPIPE被mask之外,muduo没有接管signal。当然muduo这么做是有借口的,反 正有signalfd嘛。在此我想问问各位做网络应用的同学,在你的实际项目中,不用POSIX 的signal接口而用signalfd的,有几个?而如果是从编程初学者教育的角度来看,是介绍 POSIX重要,还是介绍2.6.22引入的一个new feature重要? 而抛弃signal的处理之后,muduo自然轻松了许多,还顺带可以说一句:muduo支持高 级特性signalfd。--嗯,听起来很高级,不过signalfd不是muduo支持的,而是kernel支 持的。 一个网络编程库,timer是重中之重,比到底是用epoll还是select都重要。当然,话说回 来,再吊的库无非也就是个heap为本的数据结构在支持,无非是有些库喜欢说自己的 heap实现比别人都高效,比如haproxy。 但muduo却独辟蹊径,用timerfd,泥玛又是一个高级特性啊,很唬人的。由kernel帮你 管理timer,是不是很吊。 不仅采用了timerfd,muduo还采用了set来保存event,每个big loop里要查超时的时 候,再iterate一遍这个set。 再然后,每次加一个timer,就要冒着一次settime的syscall的风险--这还不够,还得要一 次gettimeofday。别不把syscall当不要钱的可以吗? 你也许可以跑10万个连接,但你敢加上超时的特性吗?muduo如果有做过细致的 benchmark就会知道,一个loop里最花时间的就是timer的处理。 关于muduo的timer处理,槽点太多,我就不一一细述了。回头看看timer,很显然不适 合工业应用,而给初学者做参考。。。嗯,负面参考价值很大。 嗯,今天先说这么多吧。吐槽点还很多,比如那个全功能的http范例,比如对 pthread/fork的支持,比如对内存的使用等等等等。都要一一吐过也不是不可以,不过就 要耐下性子来慢慢写就是。
  •     本书大部分都由作者的blog文章组成,内容略显杂乱,无组织性,不能算得上是一本好书,9.0的分数由理由相信是水军所为。 但是各章节内容也不能说无任何价值,都是作者的经验之谈。对我进行服务器编程不久的同学来说,还是值得一读的。
  •     去年买的这本书,到现在很多章节看了不下3遍,书中并不是讲使用muduo库,而是重点放在怎样实现一个网络库和作者多年来积累的服务端编程经验。不要去在乎什么boost库,这不是重点,重点是各种服务端技术和网络经验。说一点虚的,这是我近两年看的最认真的一本书,最有收获的一本书。如果想做服务端的同学,看看这本书绝对收获颇丰。看到有评论说muduo实现的如何不好,严重怀疑这些人没看过这本书,其实我觉得书的重点不在这。我力推这本书但是并没有用过muduo。因为我觉得重点在作者在书中大量的经验之谈,绝对醍醐灌顶,不服来辩,

精彩短评 (总计74条)

  •     本书是作者对自己blog的整理,侃侃而谈,说了不少初学者会遇到的困惑和他自己对C++网络编程的经验和认识,国内此类书还是比较少的。但是,书还是存在一些问题,作为一本出版的书应该很合理的安排章节内容,而不是直接粘来,前后章节的思路和观点明显有差异,内容也有点“散”;很多观点前作者都说“我认为”,事实上很多“我认为”是很值得商榷的!另外这本书出版时已经是C++11成文1年多了,作者似乎太急了,直接把之前写的附上,如果能更新到C++11那么可以更新很多内容,至少第4章要有很大改动。比如说到C++ memory modle,是一提及便绕过,虽然也提了《thread cannot be implemened as a library》一文,但是还能多谈谈一些细节,而不是直接说诸如“不必担心”之类的话。还有一些内容在作者的blog评论中都可以看到,不一一细说。顺便说下,我用ACE很多年了,ACE并非像作者blog上所说,而我更不认可很多对此博文的评论,都是盲目跟风,程序员要有自己的“编程世界观”不是遇到一个文笔不错的就被忽悠,紧接着跟风、吹捧。
  •     书是由博客整理而成,内容比较零散,感觉不到一本书的整体性,口水话较多。
  •     最近几年看到的最好的计算机图书。
  •     五星好评,是一本值得读两遍的书,在找工作的时候帮了我大忙,有关muduo的问题可以直接上知乎提问,作者本人会过来回答的。真心赞
  •     本书可见作者技术功底深厚。网络服务器设计模式介绍的非常清晰。
  •     作者提出一些比较个性的观点,每个人在不同的阶段或许对C++编程的风格和实践有不同的认知,也不一定需要趋同,不过一些设计思路还是值得学习和思考的。个人比较喜欢和推崇的是google leveldb的C++设计范式。也不可不得不承认和忽视的是modern c++的趋势,得跟进,不能因循守旧
  •     虽说是硕神博客的大集合,却也值得我这种长期入门级选手好好看。
  •     作为一个只会套接字编程的初学者来说,刚开始看这本书觉得不知道在说些什么,后来慢慢的了解到一些网络编程的实际应用的场景才有了点体会,这不是一本教科书,而可以算作是一本实际的工程书,里面的东西和实际的工作联系的很紧密,不像很多的教科书,看了其实也无法写出能实际用的程序。这本书是个例外,尤其是国人写的,我觉得更不简单,毕竟思维更贴近我们些。所以,如果你想了解实际的网络服务器怎么写,这本书会提供你一点思路和技巧,但是如果你只是想了解网络编程,那么还是看uinx网络编程吧
  •     陈胖子的书 要好好读
  •     由于是博文集,内容好像不是很一致,但大部分内容都蛮有价值的。
  •     陈硕大神去boolan开课,120元。有一段时间热血地差点就去开通了,冷静下来想想,120可以买好几本书了呢,于是作罢,哈哈。
  •     陈硕的博客以前也有看,出了书第一时间就买了现在很多书讲的都是非常基础的东西,非常基础的模型,但对于商业用的linux服务器编程模式以及需要注意的事项很少提及,这些知识以往大多只能通过博客文章或者实践中学习,但这本书可以让初级linux开发者对linux服务器编程有一个新的认识,这和以往的很多书不一样,不是讲基础的东西,因此需要有一定基础,例如C++语言、boost库、linux等
  •     一般般,偏基础
  •     满满的经验,准备再读。
  •     教你怎么写网络库
  •     1.在用C++设计服务器程序方面是独一无二的佳作2.使用现代C++的方法
  •     走马观花的看了一遍,没做过网络编程,很多不懂,不过一些与C++相关的问题看得还是比较过瘾的。准备读一下tcpv1和C++ primer~
  •     看不懂,帮人买的
  •     不得不承认作者的水平比我高,概念就那些但经验很重要。评论里打一星的可以手动再见了。
  •     值得多读几遍!
  •     书中一直在介绍muduo库,不太易懂
  •     了解了很多之前不知道的东西。多线程不是简单的学习几个api。实践中会遇到各种问题。而这本书刚好弥补了纯理论书籍的不足。
  •     推荐这本 以及作者的博客~
  •     只看了前面的几章,感觉写的很好,很多东西自己以前都没有考虑到。
  •     书不错,对编程水平的提高很有帮助
  •     把复杂的东西搞简单叫可以学习,把简单的东西搞复杂可以出书。 | 想读如山倒,读过如抽丝。
  •     哎这么好的书我怎么能没“读过』!?
  •     作者写东西比较认真,讲得算比较细了。在国内的技术书里还算行,不过一直对在CSDN上大篇幅写blog的人完全没好感。
  •     一本对我实际工作帮助很大的书,本书作者不仅传播了许多C++高质量工业标准的实践经验,更加可贵的是教授了一种工程师解决实际问题的方法:采用简单可依赖的方法化繁为简解决问题(对mutex和condition的讲解)
  •     好书,大家看
  •     印刷质量实在太差...有20页印刷不清,根本看不清楚
  •     游来游去
  •     作者:于洋 链接:https://www.zhihu.com/question/53769754/answer/137242022 来源:知乎 著作权归作者所有,转载请联系作者获得授权。 个人感受,这本书写的非常好,也非常用心。但悲观的说,如果一遍看不懂的话,主要是因为缺乏经验。而且,我也并不认为缺乏经验的同学会通过只看书看几次就能看懂。 我觉得技术书籍可能分为几个层次。最上层可能是哲学,中层可能是方法论,最下层是技术说明。比如,技术说明可能是,API 某某可以干什么?XX语言怎么用?这种书籍的阅读需要的经验偏低,可以直接阅读。 到了方法论这个级别,就会说,解决一个问题有很多方法。这些方法哪些是不靠谱的。哪些是常用的,哪些是最佳实践。 而这本书的出色的地方就是基本上是在方法论及以上这
  •     很棒的书,能学到很多专业知识!
  •     因为选入了很多博客上的文章,书的结构比较零散。如果把boost换成C++11就爽多了~虽然不完美,但是很多实践经验,非常好的书!
  •     第九章不能更赞
  •     书中有很多作者在工业环境下编程的经验写得很不错,概括得很好。
  •     受益良多。
  •     比较实在的入门到进阶的读物
  •     如题,很棒的书。以ACE为关键字无意中搜到作者的BLOG,很认同作者的技术观点,慎用继承,慎用OO。用上std::bind跟std::function后,思考简单了好多。
  •     发现缺少一些实践的例子,纯理论的东西太多,看到后面完全看不明白
  •     最近刚读完,确实写的不错。将apue和unp的基础知识,应用到实践中。书中给出的诸多经验很可贵。
  •     陈硕大神大作,字字珠玑,只看过一遍是远远不够的,案头书,常读常新
  •     读了分布式章节和TCP协议栈章节,写的很详细,虽然c++基础很弱,不过还是看懂了。
  •     半本C++工程实践半本mudo源码解析,虽然有些实践主张不赞同(或许和领域有关)但是这本书确实有不少干货。
  •     把自己感兴趣的内容都过了一遍。从工程实践有关的内容涨了见识。虽然不做C++,但也学到很多东西
  •     好书再买一本~
  •     书还行,只是不太适合c++或Linux基础不好的人
  •     把涉及网络编程的各方面都讲到了,不光有知识,还有经验,从中可以看到作者的取舍过程,自己从中学到很多东西。
  •     说实话,库实现的不错,书也写得很好;虽然创新性不强,但工程上借鉴的价值不错;是一本好书
  •     内容很翔实,覆盖了很多细节问题
  •     这书不错,挺不错的。
  •     大杂烩...乱..给人一种很内容牛逼但是你懂不懂是你的问题了..
  •     1. 这不是讲c++语言的,也不是讲linux系统.2. 这本书需要有一定c++基础, 懂一点网络程序设计,最好有过具体设计经验.如果满足上述条件,那么本书可以在很多方面帮你提升.1. 内存管理.2. 线程安全.3. 网络传输和具体的业务逻辑分离.4. 了解网络编程的常见模型. 分布式服务器, 客户端. ...5. 学习书中的例子, 能很好的提高自己.6. 读书的过程中,看作者旁征博引, 顿时觉得自己该多读书了.8. .......在买这本书前, 我对网络编程了解不多, 维护过一个iphone上的股票行情客户端.痛苦的很, 传输和业务缠在一起, 随意的跨线程调用. 除了问题bug一个比一个难找....看了作者陈硕的博客, 偶遇本书, 提前一个月定了. 后来啃了几个星期.把muduo移到iphone上, 期间作者对我的一些问题, 给于了耐心的解答.虽然项目还有待测试,但逻辑清晰, 对搞定项目还是有很大信心. 感谢作者. 由于目前还在啃书中, 有些地方还不理解. 多段时间再写详细的书评.如果你搞网络方面的程序设计, 不管是服务器端还是客户端, 这本书绝对值得一读.
  •     其实我不太懂网络,所以我基本上把这本书当作随笔来读的。起码就我能看得懂的部分,比如C++之类的,我觉得写的都很好。
  •     网络编程进阶非常好的一本书
  •     书还没有读完,除了关于介绍muduo库之外的部分先看完了,确实发现对于很多的想法是完全基于实践得出来的,特别是对于实践生产性代码方面的一些持否定性的观点很是赞同。对实际需要的技能的取舍也给予评价。是一本对实践工程指导很强的书籍
  •     很好的书,学习了共享指针,互斥量,编解码库,用在了项目中,很给力!
  •     不错,引用的文档也是很好的学习资料。
  •     书内容丰富,有些地方不是很认同。但很多地方用的是图片。在根本不需要用图片的地方也用要用图片。在我的retain屏幕电脑上阅读体验一点也不好。
  •     很好!我想要的,以后能用上!
  •     前一阵项目里做的东西涉及到一些linux服务器编程相关的知识,也不经意中踩到一些坑。闲下来以后通读了这本书,收益菲浅,踩过的坑也能了然于胸。 这本书理论介绍相对较少,更多为实践经验,或许有些地方不能完全苟同,但确实都可引发一些思考。
  •     还没看!等看完再来评论
  •     工程实践经验太棒了
  •     需要再仔细读一遍
  •     非常好的c++网络编程晋级指南 (特别是让我一个重来没写过C++的pythonista也看得酣畅淋漓
  •     1.不吹不黑,首先书里面的代码编译不过的,按照他给的指导无法编译出来。我遇到的错误在2010年有人就有人在作者CSDN的博客里面提出来了,但是他一直没有给出回复,由此可以看出这个作者是比较不负责的,这本书是圈钱的成分较大,这里的水军很多。如果不信我的,你们自己买来看看吧,自己的感受最重要。 2.花钱买了他与书配套的视频,更新都快一年了也没有更新完,而且视频里面他的讲解非常粗糙,大部分都是ppt的演示,没有详细的讲解,如果不信的可以自己搜索博览网买来看看。 3.作者在微博上你问他问题也是各种敷衍,大家可以去作者的微博看看。
  •     对于一个野路子C++程序员来说C++的部分还是挺有帮助的
  •     这是本多线程服务器的好书,支持陈硕,速度很快。
  •     但是建议有一定服务端开发经验的来看!
  •     读过,但是还是没吃透。。
  •     至今看过的最好的c++类的书。
  •     讲实践类的书。看了之后豁然开朗。看的UNP, linux编程相关的书后,建议看看这本 打通任督二脉。
  •     陈硕的私货还挺多的,此书实战工程经验相当丰富,估计没掉过坑的人还是吃不透,有一些设计方法我搞不懂。不过硕爷,对Lock-Free, 读写锁,递归mutex, 信号量等很鄙视,声称工作生涯以来mutex 就够用了,没见过其他的手段能提高多大的性能。不过由于作者在Morgan Stanley 设计过实时交易系统,我暂时没能力怀疑他。
 

外国儿童文学,篆刻,百科,生物科学,科普,初中通用,育儿亲子,美容护肤PDF图书下载,。 零度图书网 

零度图书网 @ 2024