<audio id="audio" title="75 | 程序员练级攻略：系统知识" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/35/95/35c7452d37fd0cdaf99098879ecb5095.mp3"></audio>

进入专业的编程领域，学习系统知识是非常关键的一部分。

首先推荐的是翻译版图书《[深入理解计算机系统](https://book.douban.com/subject/5333562/)》，原书名为《Computer Systems A Programmer’s Perspective》。不过，这本书叫做《程序员所需要了解的计算机知识》更为合适。

本书的最大优点是为程序员描述计算机系统的实现细节，帮助其在大脑中构造一个层次型的计算机系统。从最底层的数据在内存中的表示到流水线指令的构成，到虚拟存储器，到编译系统，到动态加载库，到最后的用户态应用。通过掌握程序是如何映射到系统上，以及程序是如何执行的，你能够更好地理解程序的行为为什么是这样的，以及效率低下是如何造成的。

**再强调一下，这本书是程序员必读的一本书！**

然后就是美国计算机科学家 [理查德·史蒂文斯（Richard Stevens）](https://zh.wikipedia.org/wiki/%E7%90%86%E6%9F%A5%E5%BE%B7%C2%B7%E5%8F%B2%E8%92%82%E6%96%87%E6%96%AF) 的三套巨经典无比的书。（理查德·史蒂文斯于1999年9月1日离世，终年48岁。死因不详，有人说是滑雪意外，有人说是攀岩意外，有人说是滑翔机意外。总之，家人没有透露。大师的 [个人主页](http://www.kohala.com/start/) 今天还可以访问。）

- 《[Unix高级环境编程](https://book.douban.com/subject/1788421/)》。
- 《Unix网络编程》 [第1卷 套接口API](https://book.douban.com/subject/1500149/) 、[第2卷 进程间通信](https://book.douban.com/subject/4118577/) 。
- 《[TCP/IP详解 卷I 协议](https://book.douban.com/subject/1088054/)》。

这几本书的地位我就不多说了，你可以自己看相关的书评。但是，这三本书可能都不容易读，一方面是比较厚，另一方面是知识的密度太大了，所以，读起来有点枯燥和乏味。但是，这没办法，你得忍住。

这里要重点说一下《TCP/IP详解》这本书，是一本很奇怪的书。这本书迄今至少被 [近五百篇学术论文引用过](http://portal.acm.org/citation.cfm?id=161724) 。这本写给工程师看的书居然被各种学院派的论文来引用，也是很神奇的一件事了。而且，虽然理查德·史蒂文斯不是TCP的发明人，但是这本书中把这个协议深入浅出地讲出来，还画了几百张时序图，也是令人叹为观止了。

如果你觉得上面这几本经典书比较难啃，你可以试试下面这些通俗易懂的（当然，如果读得懂上面那三本的，下面的这些也就不需要读了）。

- 《[Linux C编程一站式学习](https://book.douban.com/subject/4141733/)》。
- 《[TCP/IP网络编程](https://book.douban.com/subject/25911735/)》。
- 《[图解TCP/IP](https://book.douban.com/subject/24737674/)》，这本书其实并不是只讲了TCP/IP，应该是叫《计算机网络》才对，主要是给想快速入门的人看的。
- 《[The TCP/IP Guide](http://www.tcpipguide.com/free/index.htm)》，这本书在豆瓣上的评分9.2，这里给的链接是这本书的HTML英文免费版的，里面的图画得很精彩。

另外，学习网络协议不单只是看书，你最好用个抓包工具看看这些网络包是什么样的。所以，这里推荐一本书《[Wireshark数据包分析实战](https://book.douban.com/subject/21691692/)》。在这本书中，作者结合一些简单易懂的实际网络案例，图文并茂地演示使用Wireshark进行数据包分析的技术方法，可以让我们更好地了解和学习网络协议。当然，也拥有了一定的黑客的技能。

看完《Unix高级环境编程》后，你可以趁热打铁看看《[Linux/Unix系统编程手册](https://book.douban.com/subject/25809330/)》或是罗伯特·拉姆（Robert Love）的 [Linux System Programming 英文电子版](http://igm.univ-mlv.fr/~yahya/progsys/linux.pdf) 。其中文翻译版[Linux系统编程](https://book.douban.com/subject/25828773/) 也值得一读，虽然和《Unix高级环境编程》很像，不过其主要突出的是Linux的一些关键技术和相关的系统调用。

关于TCP的东西，你还可以看看下面这一系列的文章。

- [Let’s code a TCP/IP stack, 1: Ethernet &amp; ARP](http://www.saminiir.com/lets-code-tcp-ip-stack-1-ethernet-arp/)
- [Let’s code a TCP/IP stack, 2: IPv4 &amp; ICMPv4](http://www.saminiir.com/lets-code-tcp-ip-stack-2-ipv4-icmpv4/)
- [Let’s code a TCP/IP stack, 3: TCP Basics &amp; Handshake](http://www.saminiir.com/lets-code-tcp-ip-stack-3-tcp-handshake/)
- [Let’s code a TCP/IP stack, 4: TCP Data Flow &amp; Socket API](http://www.saminiir.com/lets-code-tcp-ip-stack-4-tcp-data-flow-socket-api/)
- [Let’s code a TCP/IP stack, 5: TCP Retransmission](http://www.saminiir.com/lets-code-tcp-ip-stack-5-tcp-retransmission/)

**对于系统知识，我认为主要有以下一些学习要点。**

- 用这些系统知识操作一下文件系统，实现一个可以拷贝目录树的小程序。
- 用fork / wait / waitpid写一个多进程的程序，用pthread写一个多线程带同步或互斥的程序。比如，多进程购票的程序。
- 用signal / kill / raise / alarm / pause / sigprocmask实现一个多进程间的信号量通信的程序。
- 学会使用gcc和gdb来编程和调试程序（参看我的《**用gdb调试程序**》[一](https://blog.csdn.net/haoel/article/details/2879)、[二](https://blog.csdn.net/haoel/article/details/2880)、[三](https://blog.csdn.net/haoel/article/details/2881)、[四](https://blog.csdn.net/haoel/article/details/2882)、[五](https://blog.csdn.net/haoel/article/details/2883)、[六](https://blog.csdn.net/haoel/article/details/2884)、[七](https://blog.csdn.net/haoel/article/details/2885)）。
- 学会使用makefile来编译程序（参看我的《**跟我一起写makefile**》[一](https://blog.csdn.net/haoel/article/details/2886)、[二](https://blog.csdn.net/haoel/article/details/2887)、[三](https://blog.csdn.net/haoel/article/details/2888)、[四](https://blog.csdn.net/haoel/article/details/2889)、[五](https://blog.csdn.net/haoel/article/details/2890)、[六](https://blog.csdn.net/haoel/article/details/2891)、[七](https://blog.csdn.net/haoel/article/details/2892)、[八](https://blog.csdn.net/haoel/article/details/2893)、[九](https://blog.csdn.net/haoel/article/details/2894)、[十](https://blog.csdn.net/haoel/article/details/2895)、[十一](https://blog.csdn.net/haoel/article/details/2896)、[十二](https://blog.csdn.net/haoel/article/details/2897)、[十三](https://blog.csdn.net/haoel/article/details/2898)、[十四](https://blog.csdn.net/haoel/article/details/2899)）。
- Socket的进程间通信。用C语言写一个1对1的聊天小程序，或是一个简单的HTTP服务器。

# C10K 问题

然后，当你读完《Unix网络编程》后，千万要去读一下 “[C10K Problem](http://www.kegel.com/c10k.html) （[中文翻译版](https://www.oschina.net/translate/c10k)）”。提出这个问题的人叫丹·凯格尔（Dan Kegel），目前在Google任职。

他从1978年起开始接触计算机编程，是Winetricks的作者，也是Wine 1.0的管理员，同时也是Crosstool（ 一个让 gcc/glibc 编译器更易用的工具套件）的作者。还是Java JSR 51规范的提交者并参与编写了Java平台的NIO和文件锁，同时参与了RFC 5128标准中有关NAT穿越（P2P打洞）技术的描述和定义。

C10K问题本质上是**操作系统处理大并发请求的问题**。对于Web时代的操作系统而言，对于客户端过来的大量的并发请求，需要创建相应的服务进程或线程。这些进程或线程多了，导致数据拷贝频繁（缓存I/O、内核将数据拷贝到用户进程空间、阻塞）， 进程/线程上下文切换消耗大，从而导致资源被耗尽而崩溃。这就是C10K问题的本质。

了解这个问题，并了解操作系统是如何通过多路复用的技术来解决这个问题的，有助于你了解各种I/O和异步模型，这对于你未来的编程和架构能力是相当重要的。

另外，现在，整个世界都在解决C10M问题，推荐看看 [The Secret To 10 Million Concurrent Connections -The Kernel Is The Problem, Not The Solution](http://highscalability.com/blog/2013/5/13/the-secret-to-10-million-concurrent-connections-the-kernel-i.html) 一文。

# 实践项目

我们已经学习完了编程语言、理论学科和系统知识三部分内容，下面就来做几个实践项目，小试牛刀一下。实现语言可以用C、C++或Java。

实现一个telnet版本的聊天服务器，主要有以下需求。

- 每个客户端可以用使用`telnet ip:port`的方式连接到服务器上。
- 新连接需要用用户名和密码登录，如果没有，则需要注册一个。
- 然后可以选择一个聊天室加入聊天。
- 管理员有权创建或删除聊天室，普通人员只有加入、退出、查询聊天室的权力。
- 聊天室需要有人数限制，每个人发出来的话，其它所有的人都要能看得到。

实现一个简单的HTTP服务器，主要有以下需求。

- 解释浏览器传来的HTTP协议，只需要处理URL path。
- 然后把所代理的目录列出来。
- 在浏览器上可以浏览目录里的文件和下级目录。
- 如果点击文件，则把文件打开传给浏览器（浏览器能够自动显示图片、PDF，或HTML、CSS、JavaScript以及文本文件）。
- 如果点击子目录，则进入到子目录中，并把子目录中的文件列出来。

实现一个生产者/消费者消息队列服务，主要有以下需求。

- 消息队列采用一个Ring-buffer的数据结构。
- 可以有多个topic供生产者写入消息及消费者取出消息。
- 需要支持多个生产者并发写。
- 需要支持多个消费者消费消息（只要有一个消费者成功处理消息就可以删除消息）。
- 消息队列要做到不丢数据（要把消息持久化下来）。
- 能做到性能很高。

# 小结

到今天，我们已经学习完了专业编程方面最为重要的三部分内容：编程语言、理论学科和系统知识，我们针对这些内容做个小结。如果想看完我推荐的那些书和知识，并能理解和掌握，我估计怎么也得需要4-5年的时间。嗯，是的，就是一个计算机科学系科班出身的程序员需要学习的一些东西。这其中，最重要的是下面这几点。

**编程语言**。以工业级的C、C++、Java这三门语言为主，这三门语言才是真正算得上工业级的编程语言，因为有工业级的标准化组织在控制着这几门语言，而且也有工业级的企业应用。尤其是Java，还衍生出了大量的企业级架构上的开源生态。你至少需要掌握C语言和Java语言，这对你以后面对各式各样的编程语言是非常重要的。

此外，还推荐学习Go语言，它已成为云计算领域事实上的标准语言，尤其是在Docker、Kubernetes等项目中。而且，Go语言在国内外一些知名公司中有了一定的应用和实践，并且其生态圈也越来越好。

**算法和数据结构**。这个太重要了，尤其是最基础的算法和数据结构，这是任何一个称职的程序员都需要学习和掌握的。你必需要掌握。

**计算机的相关系统**。你至少要掌握三个系统的基础知识，一个是操作系统，一个是网络系统，还有一个是数据库系统。它们分别代表着计算机基础构架的三大件——计算、存储、网络。

如果你能够走到这里，把前面的那些知识都了解了（不用精通，因为精通是需要时间和实践来慢慢锤炼出来的，所以，你也不用着急），那么你已经是一个合格的程序员了，而且你的潜力和可能性是非常非常高的。

如果经历过这些比较枯燥的理论知识，而且你还能有热情和成就感，那么我要恭喜你了。因为你已经超过了绝大多数人，而且还是排在上游的比较抢手的程序员了。我相信你至少可以找到年薪50万以上的工作了。

但是，你还需要很多的经验或是一些实践，以及一些大系统大项目的实际动手的经验。没关系，我们后面会有教你怎么实操的方法和攻略。

但是，往后面走，你需要开始需要术业有专攻了。下面给一些建议的方向。

- **底层方向**：操作系统、文件系统、数据库、网络……
- **架构方向**：分布式系统架构、微服务、DevOps、Cloud Native……
- **数据方向**：大数据、机器学习、人工智能……
- **前端方向**：你对用户体验或是交互更感兴趣，那么你走前端的路吧。
- **其它方向**：比如，安全开发、运维开发、嵌入式开发……

这些方向你要仔细选择，因为一旦选好，就要勇往直前地走下去，当然，你要回头转别的方向也没什么问题，因为你有前面的这些基础知识在身，所以，不用害怕。只是不同的方向上会有不同的经验积累，经验积累是看书看不来的，这个是转方向的成本。

下篇文章，我们将进入《软件设计篇》。敬请期待。

下面是《程序员练级攻略》系列文章的目录。

- [开篇词](https://time.geekbang.org/column/article/8136)
<li>入门篇
<ul>
- [零基础启蒙](https://time.geekbang.org/column/article/8216)
- [正式入门](https://time.geekbang.org/column/article/8217)

- [程序员修养](https://time.geekbang.org/column/article/8700)

- [编程语言](https://time.geekbang.org/column/article/8701)
- [理论学科](https://time.geekbang.org/column/article/8887)
- [系统知识](https://time.geekbang.org/column/article/8888)

- [软件设计](https://time.geekbang.org/column/article/9369)

- [Linux系统、内存和网络（系统底层知识）](https://time.geekbang.org/column/article/9759)
- [异步I/O模型和Lock-Free编程（系统底层知识）](https://time.geekbang.org/column/article/9851)
- [Java底层知识](https://time.geekbang.org/column/article/10216)
- [数据库](https://time.geekbang.org/column/article/10301)
- [分布式架构入门（分布式架构）](https://time.geekbang.org/column/article/10603)
- [分布式架构经典图书和论文（分布式架构）](https://time.geekbang.org/column/article/10604)
- [分布式架构工程设计(分布式架构)](https://time.geekbang.org/column/article/11232)
- [微服务](https://time.geekbang.org/column/article/11116)
- [容器化和自动化运维](https://time.geekbang.org/column/article/11665)
- [机器学习和人工智能](https://time.geekbang.org/column/article/11669)
- [前端基础和底层原理（前端方向）](https://time.geekbang.org/column/article/12271)
- [前端性能优化和框架（前端方向）](https://time.geekbang.org/column/article/12389)
- [UI/UX设计（前端方向）](https://time.geekbang.org/column/article/12486)
- [技术资源集散地](https://time.geekbang.org/column/article/12561)


