1. 第一阶段 学好 C 语言和 Linux
1.1 学好 C 语言
无论你是科班还是非科班,建议你一定要学好 C 语言,它应该作为你必须掌握好的语言。你要熟悉 C 语言的基本语法,包括:
-
顺序、条件、循环三大控制语句
-
C 中几大基元数据类型的用法
-
熟悉掌握数组的用法
-
熟练掌握指针的用法
-
熟练掌握结构体、枚举、联合等数据类型的用法
-
熟练使用常用 C 库函数,如控制台输入输出流、字符串操作、文件操作、时间函数等等
以上阶段算是启蒙阶段,在这个阶段,是基础编程语法的学习,当然,你不仅仅要掌握这些基本语法,你还要反复练习。
我当年总是不理解 C 语言中的一些概念和原理,后来我的学长推荐了我一本书——《C语言程序设计 现代方法》,并且我利用这本书也考上了相关的专业的研究生。这本书成了我迷茫时的一座灯塔,今天我把它推荐给学弟学妹们。
这本书在国外是作为经典大学教材的,两位译者一位是亚洲理工大学,一位是中科院,书翻译的也很地道。
当然,如果你熟悉了 C 语言的常用语法后,你想进一步针对 C 语言的一些细节和高级特性进行查漏补缺,推荐看看《C 专家编程》。
无论是 C 还是 C++,指针一直是很多初学者的老大难,可以把指针作为一个专题彻底搞明白,关于这方面也有一本非常好的书,这本书的语言写的也非常通俗易懂,我当年读完之后,对指针再无疑惑,书名叫《C 和指针》。
指针是 C 语言乃至整个操作系统的灵魂,一定要理解好。
1.2 学习 Linux 常用操作
一、多接触,多操作
根据我自己的经历来说一下,我当年从 Windows 转到 Linux,虽然勉强入职了,但是非常害怕工作中因不熟悉 Linux 的操作被同事质疑。后来,我就在自己的电脑上撞了一个 CentOS,然后自己玩,再业余时间结合一些 Linux 系统学习资料/图书学习,没过多久也熟悉了。
通常情况下,记不住 Linux 命令有如下几种原因:
原因一:刚接触,习惯了之前的图形化界面操作,不习惯 Linux 各种命令行操作,心存恐惧之心。
原因二:不经常使用 Linux,操作生疏。
如果是上述两个原因的话,建议读者多玩一玩 Linux 操作系统,可以在自己电脑上通过虚拟机安装一个 Linux 系统(如 CentOS、Ubuntu)。自己在虚拟机中安装 Linux 系统的好处是你可以任意把玩这个系统,只要愿意可以搞清楚这个系统的方方面面。
如果你的机器配置不行,或者不愿意自己安装 Linux 系统,可以花一点费用去各大云主机上(如阿里云、腾讯云)买一些低配的 Linux 主机空间来玩,然后用 XShell、SecureCRT 这样的工具去远程登录到云主机上去玩。下图就是我使用 SecureCRT 连接到我的阿里云主机上进行操作:
原因三:命令比较复杂,用法比较多。
如果是这个原因,建议先搞懂这个命令的用法(例如一些常见功能),实在太复杂的命令,只要知道其有哪些用途,需要用的时候去查一下帮助文档就可以了,Linux 的 man 手册要多查多用。
举个例子,我开始学习 Linux 的 lsof 命令时,总是记不住这个命令的一些参数,后来,我总结了一下,我的使用场景大多数情况下就是用来查看操作系统的 IP 地址和端口号信息,其常用的参数也就 -i 和 -Pn。
[root@myaliyun ~]# lsof -i -Pn
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ntpd 522 ntp 16u IPv4 12575 0t0 UDP *:123
ntpd 522 ntp 17u IPv6 12576 0t0 UDP *:123
ntpd 522 ntp 18u IPv4 12596 0t0 UDP 127.0.0.1:123
ntpd 522 ntp 20u IPv4 15777 0t0 UDP 172.16.210.241:123
dhclient 743 root 6u IPv4 13435 0t0 UDP *:68
mysqld 1256 mysql 13u IPv4 16416 0t0 TCP *:3306 (LISTEN)
sshd 1485 root 3u IPv4 17012 0t0 TCP *:22 (LISTEN)
nginx 1723 root 6u IPv4 26732 0t0 TCP *:80 (LISTEN)
nginx 1724 root 6u IPv4 26732 0t0 TCP *:80 (LISTEN)
server 11761 root 4u IPv4 13328465 0t0 TCP 172.16.210.241:39312->118.178.56.143:8080 (ESTABLISHED)
server 12402 root 4u IPv4 13328465 0t0 TCP 172.16.210.241:39312->118.178.56.143:8080 (ESTABLISHED)
fileserve 18483 root 5u IPv4 10028642 0t0 TCP *:20001 (LISTEN)
imgserver 18496 root 6u IPv4 10028977 0t0 TCP *:20002 (LISTEN)
route_ser 19613 root 5u IPv4 833919 0t0 TCP *:8200 (LISTEN)
file_serv 19644 root 6u IPv4 834017 0t0 TCP *:8600 (LISTEN)
file_serv 19644 root 7u IPv4 834018 0t0 TCP 127.0.0.1:8601 (LISTEN)
msfs 20274 root 5u IPv4 834510 0t0 TCP *:8700 (LISTEN)
AliYunDun 21538 root 20u IPv4 11768616 0t0 TCP 172.16.210.241:60868->100.100.30.26:80 (ESTABLISHED)
sshd 23923 root 3u IPv4 13533428 0t0 TCP 172.16.210.241:22->116.236.159.130:56739 (ESTABLISHED)
sshd 31548 root 3u IPv4 13537639 0t0 TCP 172.16.210.241:22->116.236.159.130:61055 (ESTABLISHED)
当然,这个命令还可以在一些情况下恢复被删除的 Linux 文件,那我知道有这么回事,我实际需要的时候去查一下帮助文档就可以了。
再比如 nc 命令,我用的最常用的参数就是 -v -l -p。
但是像 awk 命令的具体格式我是实在记不住的,我每次用的时候都是去查。
当然,良好的英语水平也能帮助你记忆一些 Linux 命令,如 ls => list,lsof => list opened file。
其实 Linux 系统常用的命令并不多。
二、理解一些 Linux 原理
有一些 Linux 操作你一定要理解其背后的原理,比如经常有一些学生来面试,告诉我熟悉 Linux 系统,我就问他 Linux 下如何判断一个文件是可执行文件,很多同学只知道可以使用 chmod +x 授予执行权限,却不知道这个权限怎么看。
三、多积累一些小技巧
除了系统地阅读一些 Linux 书籍之外,平常可以找一些 Linux 各种小技巧的文章来看一看。比如一些同学可能不知道 vim 中如何复制粘贴、如何撤销一个操作、命令行中如何在从一键跳转到命令行的开始或者结尾处、如何使用命令与 Windows 系统之间传输文件等等。
这些技巧可以自己收集于网络,也可以自己细心观察学习自你的同学、同事等等。
四、推荐一些学习 Linux 的资源
就事论事,Linux 系统并不比 Windows 难多少,克服恐惧,一定能上手的。
推荐书籍:
《Linux 就是这个范儿》
《鸟哥的 Linux 私房菜基础篇》
《鸟哥的Linux私房菜服务器架设篇》
推荐视频:
linux操作系统入门到精通全套教程(含pdf文档),linux小白、linux零基础也能快速学会https://www.bilibili.com/video/BV1Sg4y1X7Ap/
2. 第二阶段 学好算法和数据结构
如果你想毕业后进大厂,建议好好学习算法和数据结构。学习算法和数据一定不能急功近利,算法和数据结构的知识一定要作为一个长期的学习目标。
对于非科班的同学,由于没有像科班同学那样接受到系统的学习,一定要找一两本经典书籍系统地学习下常见的算法理论、思想和常用的数据结构知识。等熟悉了这块的知识,再适当地刷一些算法题目或者做一些算法练习。
对于校招或者工作年限不长的同学,面试大厂,必然有一些算法和数据结构的题目。
而且对于校招,通常这块答的不好,基本就被一票否决了。这也是我建议那些参加校招的同学要好好准备算法和数据结构的题目了。说到这里,为一些学历不错但是因为在校招前不认真准备这块、最终无缘大厂的同学感到惋惜,懒惰两个月,影响职业生涯一辈子。
我目前人在大厂做开发,有时候也担任面试官。从面试官的角度来说,大多数技术岗位算法这块的题目并不难,但是一定要在面试前好好准备一下。
另外,很多算法题其实就是《剑指 offer》上的原题。
推荐视频教程:
c/c++后端开发必学:数据结构与算法(红黑树、B-/B+树、时间轮、跳表、hash、二叉树、布隆过滤器...)https://www.bilibili.com/video/BV1nc411K7vw/
3. 第三阶段 学习一门重型编程语言
如果你想成为开发高手,必须要学一门重型编程语言傍身,可以是 C/C++/Java,只会 Python 和 php 等是远远不够的。
3.1 如果是学习 C++,可以这么学:
C++ 语言本身涉及到的知识点比较多,需要强调的是,既然是学习,请抛弃各种总结经验技巧的面经,逐个掌握 C++ 语言的各个知识点,包括但不局限于:
-
指针和引用的概念
-
指针与内存关系
-
程序编译过程,静态链接库和动态链接库
-
static、const、#define的用法和区别
-
C和C++区别
-
内存中的栈和堆分配
-
面向对象理解
-
访问限定符 public/protected/private
-
构造函数/析构函数/拷贝构造
-
多态
-
虚函数与纯虚函数、虚函数实现机制、虚函数表
-
继承原理、虚继承、菱形继承
-
new/delete和malloc/free
-
重载、重写和覆盖
-
类型转换方式
-
RAII 与 pimpl 惯用法
-
内存溢出和内存泄漏
-
STL标准模板库
-
迭代器、空间配置器理解
-
常用容器特点、用法以及底层实现vector、list、deque、set、map、unorderedmap
C++11/14/17 新标准也慢慢成为主流,这块也要熟悉,要熟悉新标准常用的语法与新功能,包括:另外,时至今日,你一定要熟悉 C++11/14/17 常用的语言特性和类库,这里简单地列一下:
-
左值/右值/std::move/std::forward
-
统一的类成员初始化语法与 std::initializer_list
-
注解标签(attributes)
-
final/override/=default/=delete 语法
-
auto 关键字
-
Range-based 循环语法
-
结构化绑定
-
stl 容器新增的实用方法
-
std::thread
-
线程局部存储 thread_local
-
线程同步原语 std::mutex、std::condition_variable 等
-
原子操作类
-
智能指针类
-
std::bind/std::function
C++11/14 网上的资料已经很多了,C++17 的资料不多,重点掌握的还是 C++11 引入的各种实用特性,这就给读者推荐一些我读过的书(文末有完整的书单及下载方式):
-
《深入理解 C++11:C++11 新特性解析与应用》
-
《深入应用 C++11:代码优化与工程级应用》
-
《C++17 完全指南》
-
《Cpp 17 in Detail》
4. 第四阶段 熟悉编程语言相关的开发工具链
熟悉该语言的相关的 IDE 开发环境,如果是 C++ 开发,Windows上我推荐 Visual Studio,Mac 上可以使用Subline 或者VSCode,如果你最终的程序需要在 Linux 跑,你需要熟悉 cmake/make/gcc/g++/gdb 工具链,vim 的基本操作也要熟悉,但绝对不要直接在 vim 中写代码,纯属浪费时间,实际企业级开发也没人会这么做。这里强调一下,如果可能,至少要熟悉 Visual Studio 和 gdb 调试,调试需要掌握哪些内容呢?
建议掌握:
-
如何启动和结束调试
-
如何添加/删除/启用/禁用断点(包括普通断点、条件断点和数据断点)
-
如何查看当天断点下的调用对战
-
如何查看程序运行过程中的线程信息(这块可以放到下文再学)
-
如何查看某个变量的内存值
掌握了一门编程语言加其开发的工具链,你的想法就可以通过动手变为现实了。熟悉了 C/C++ 语言和其相关的开发工具链,接下来你可以根据你的兴趣学习相关的开发知识了。
接下来就挨个学计算机学科的各类基础知识了。如果你是非科班,也建议自己找点经典的书籍系统地学习一下。下面挨个说一下这几大方面的基础知识。
5. 第五阶段 熟悉操作系统原理和常用 API 接口
5.1 学习操作系统常用 API
除了 C++ 本身的语法,你还需要学习操作系统的常用 API 接口函数、Socket 编程等等,不然可能还是很难写出有用的程序,这也是为什么很多同学在学习完 C++ 语言之后,始终只会写黑洞洞的命令行程序。很多人说,操作系统的 API 接口不用刻意学习,根据我个人的经验,我反对这一观点,操作系统的很多 API 涉及到很多操作系统原理和使用技巧,绝非是想用的时候去查一查就可以了。就和开卷考试一样,如果不熟悉,且不说不知道如何查、在哪查,就算查到了,是否可以用好又是另外一回事了。
虽然现在 C++ 自带的 stl 库封装的操作系统的功能已经日趋完善,但是做 C++ 开发不熟悉常见操作系统的 API 函数是行不通的。我上学的时候,C++ 语言本身学的不错,但是我总觉得实现自己想要的功能很困难,例如做一个五子棋项目,如何在棋盘上画方格,做一个网盘项目,如何高效的利用多线程分割和组装文件。当年,在看别人开源项目时,我发现,让我觉得困难的并不是 C++ 语言,而是各种我不熟悉的操作系统 API 和给它们传递的参数。
对于 Linux 系统,我入门的时候看的是 Robert Love 的《Linux 系统编程》,这本书介绍了 Linux 系统上常用的 API 函数和背后的原理。Robert Love 是 Google 的工程师,他也《Linux 内核设计与实现》一书的作者。
Windows 系统 API 学习,我推荐《Windows 程序设计(第五版)》和 《Windows 核心编程》。
说了这么多,强调熟悉操作系统 API 的重要性,我来举个例子吧,假设我们要开发一款像电驴一样的商业软件需要,软件界面如下图:
电驴 - 源码下载:
链接:https://pan.baidu.com/s/1aZl1tfqE7D_iDj1cn5aUcg 提取码:v83h
如上图所示,假设操作系统选择 Windows,使用语言使用 C++,这就要求您必须熟悉 C++ 常用的语法,如果还不熟悉,就需要补充这方面的知识。
在熟悉 C++ 语法的前提下,从这款产品实现技术来看,我们的目标产品分为 UI 和网络通信部分。下面将详细介绍这两部分。
UI 部分
对于 UI 部分,我们的认识是,这里需要使用 Windows 的窗口技术。可以直接使用原生的 Win 32 API 来制作自己的界面库,也可以选择一些熟悉的界面框架,如 MFC、WTL、Duilib、wxWidgets 等。无论您是在阅读别人的项目还是需要自己开发这样的项目,在确定了这款软件使用的 UI 库(或者使用原生 Win 32 API),您就需要对 Windows 的窗口、对话框、消息产生、派发与处理机制进行了解。同样的道理,如果不熟悉您需要补充相关的知识(关于这一点,下文不再赘述)。
接着,根据上图中的软件功能,大致分为三大模块,即资源、下载和分享。这三大块是可以使用一个 Windows Tab 控件去组织,这个时候您需要了解 Windows Tab 控件的特性。
-
对于资源模块,本质上是一个窗口中嵌入了一个浏览器控件(WebBrowser 控件),那么您需要了解这一个功能点的相关知识。当用户点击了某个列表中某个具体的资源,可以对其进行下载。这就又涉及到 WebBrowser 控件与 C++ 宿主程序的交互了,那么如何实现呢?可以选择使用 ActiveX 技术,也可以使用 JavaScript 与 C++ 交互技术。
-
再来看下载模块,当产生一个下载操作时,界面上会产生以下下载列表,每个列表项会实时显示下载进度、下载速率等参数,同时正在下载的项目也可以被暂停、停止和删除。那么这又涉及到 ListView 控件的相关功能,以及 ListView 如何与后台网络通信的逻辑交互。
-
分享模块是将本地资源分享到服务器或者给其他用户。界面左侧是文件系统的一个快照,那么这又涉及到如何遍历文件系统(了解枚举文件系统的 API),右侧也是一个 ListView 控件,这里不再赘述。
网络通信部分
网络通信部分,主要有两大块,第一个是程序启动时,与服务端的交互;第二个就是文件下载与分享的 P2P 网络。您在阅读或开发的过程中,如果对这些技术比较陌生,您需要补充这些知识,具体的就是 Socket 的各种 API 函数,以及基于这些 API 逻辑的组合。当然可能也会用到操作系统平台所特有的网络 API 函数,如 WSAAsyncSelect 网络模型。
另外一点,网络通信部分如何与 UI 部分进行数据交换,是使用队列?全局变量?或者相应的 Windows 操作平台提供的特殊通信技术,如 PostMessage 函数、管道?如果使用队列,多线程之间如何保持资源的一致性和解决资源竞态,使用 Event、CriticalSection、Mutex、Semaphore 等?
当然,笔者这里只列举了这个软件的主干部分,还有许多方方面面的细节需要考虑。这就需要读者根据自己的情况,斟酌和筛选了。您想达到什么目的,就要去学习和研究相关的代码。
总结起来,可以得到如下公式:
一款 C++ 软件 = C++ 语法 + 操作系统 API 函数调用
学习操作系统的接口不仅是学习相关操作系统 API,同时也是在培养自己的动手和实践能力。常用的操作系统 API 并不多,以多线程相关的为例,Windows 系统提供的线程同步原语常用的有临界区、Event、互斥体、信号量等,Linux 常用的有互斥体、读写锁、信号量和条件变量,掌握这些并不困难,你只要花一周时间挨个地学习联系一下,很快就能掌握。
熟悉了常用操作系统的 API 之后,你就可以自由地写出自己想要的程序了,这个时候处于初级的通透状态,例如,你可以随手写出这样一个功能的程序:
主线程创建一个新的工作线程,等待工作线程获取系统时间后写入文件;主线程从文件中读取时间内容显示出来。
这个例子中,我们用到了创建线程的 API、线程等待与通知 API、获取系统时间的 API、显示到控制台的 API
在 Windows 上,我们用到:
-
CreateThread
-
WaitForSingelObject
-
GetSystemTime
-
CreateEvent/SetEvent
-
std::cout
在 Linux 上,我们可以使用:
-
pthread_create
-
pthread_mutex_init/pthread_cond_init/pthread_cond_destroy/pthread_cond_wait
-
time
-
std::cout
这么一分析是不是觉得一下子清晰起来,因为 C/C++ 这么编程语言不是功能完备性的,如果 C/C++ 的 C 库或者 stl 本身没有提供这些功能,你不得不使用操作系统的 API。
如果你掌握到这个阶段,恭喜你,你已经可以去胜任中小企业的 C/C++ 开发了。所以,我推荐的这条路线,如果你认真学习,保底能让你找到一份小公司的 C++ 开发工作的。
5.2 学习操作系统 API 也包括学习多线程编程
这块与上文有一点重叠,我们再次说一下。多线程知识,你需要掌握理解线程与进程的关系、熟练使用常用的线程同步技术。推荐的一种学习方式,就是找一个开源项目,使用调试器跑起来,然后看看这个进程有多少线程,每个线程在何时被创建,每个线程的作用是什么,线程之间如何通信的。这也是上文建议你熟练掌握调试器的原因。
推荐看游双的《Linux 高性能服务器编程》多线程相关章节,了解操作系统提供的常用多线程同步原语。
5.3 学习操作系统 API 也包括熟悉操作系统原理
操作系统原理无论是面试还是自我提高的五大基础之一,我的建议学习操作系统知识时,不一定要看完所有操作系统书籍,但一定将一些基础概念(如进程、线程、内存模式等)看懂、理清。Tanenbaum.A.S《现代操作系统》是一本讲解操作系统理论不错的书,作者 Tanenbaum.A.S 是 Linux 内核创始人 Linus Torvalds 的老师。
你如果还有时间强烈推荐看看俞甲子的《程序员的自我修养:链接、装载与库》。这本书同时涉及到了 Windows 和 Linux 两个操作系统平台,用各种辅助工具剖析了程序从源码到二进制文件再到装载到进程地址空间里面的各个细节,甚至连进程地址空间中的堆结构、栈结构也分析得清清楚楚,同时也分析了 C Runtime(CRT)、glibc 这样的操作系统接口库的原理和执行逻辑,是一本实实在在帮你实战操作系统原理的好书。
当然,学有余力的同学,可以进一步了解一些关于操作系统的模式(如实模式、保护模式)、系统的启动与初始化、虚拟内存与物理内存、内存分表分页机制、进程与线程的调度算法等知识。
想要做好开发必须要学习操作系统的原理。学习操作系统原理不一定要看完所有操作系统书籍,但一定将一些基础概念(如进程、线程、内存模式等)看懂、理清,否则稍微复杂点的 C++ 程序还是会无从下手,这里推荐Tanenbaum.A.S《现代操作系统》。
从一个 .cpp 文件到可执行程序,经历了哪些阶段,每个阶段做了什么事,可执行文件里面有什么,可执行文件如何被装载到进程地址空间变成可执行的进程的,这些是 C++ 开发者要搞清楚的。强烈推荐看看俞甲子的《程序员的自我修养:链接、装载与库》,这本书同时涉及到了 Windows 和 Linux 两个操作系统平台,用各种辅助工具剖析了程序从源码到二进制文件再到装载到进程地址空间里面的各个细节,甚至连进程地址空间中的堆结构、栈结构也分析得清清楚楚,同时也分析了 C Runtime(CRT)、glibc 这样的操作系统接口库的原理和执行逻辑,是一本实实在在帮你实战操作系统原理的好书。搞 C++ 开发,不看这本书,学尽 C++ 也枉然。
6. 第六阶段 学习汇编
如果你熟练掌握汇编,你就比其他人多很多优势,你会能透彻地知道你写的每一行 C/C++ 代码背后的机器指令的效率。无论是做安全工程还是自己技术提升上都是非常不错的。这里推荐一本王爽老师的《汇编语言(第 3 版)》,这本书不厚,语言通俗易懂,你也不用刻意去记忆,基本上当小说书看一下就能很快看完了。汇编实战类图书还有另外一本《老码识途:从机器码到框架的系统观逆向修炼之路》。我个人是非常喜欢这本书的。当年读这本书的时候,真的有一种“笑看妻子愁何在?漫卷诗书喜欲狂”的感觉。
一个不懂汇编的 C++ 程序不是真的 C++ 程序员,如果你不懂汇编,你很难搞得懂 C++ 的函数调用方式,很难搞得懂栈的结构,很难搞的清楚写 switch-case 语句时,怎样布局 case 分支效率才高等等。
如果你熟练掌握汇编,你就比其他人多很多优势,你会能透彻地知道你写的每一行 C/C++ 代码背后的机器指令的效率。无论是做安全工程还是自己技术提升上都是非常不错的。这里推荐一本王爽老师的《汇编语言(第 3 版)》,这本书不厚,语言通俗易懂,你也不用刻意去记忆,基本上当小说书看一下就能很快看完了。
汇编实战类图书还有另外一本《老码识途:从机器码到框架的系统观逆向修炼之路》。我个人是非常喜欢这本书的。我上学的时候发现这本书欣喜之致,连着我在宿舍读了两个星期,将这本书读完。
这本书豆瓣评分 9.1 分:
7. 第七阶段 学习计算机网络和 socket 编程
学习计算机网络要从以下三个方面学习:
7.1 学习计算机网络理论知识
计算机网络编程你需要掌握基础的如三次握手和四次挥手的过程以及各个状态值,我建议使用 tcpdump 命令实际抓下包就一目了然了,然后就是网络分层,各层的用途,重点熟悉下 TCP/IP 层相关的知识,还有就是 TCP/UDP 的区别,TCP 的滑动窗口机制、拥塞控制算法、TCP 的保序、重传、确认机制。
学习这些知识的时候,一定不要死记硬背,注重理解。我近来面试了一部分学历学校非常好的同学,然而,在问到这块的知识时却大失所望。例如,有的同学只是单纯把三次握手背下来了,我稍微变通一下他就不知道怎么回答了:
-
如果连接一个目标主机不存在的 IP 地址握手过程是怎样的?连接一个目标 IP 存在但是端口号不存在的主机又是怎样的握手过程呢?
-
A 机器上的进程与 B 机器上的进程进行网络通信,分别经历了哪些网络层。
7.2 学习 Socket 编程
Socket 编程你需要先掌握常用的 Socket API,包括但不局限于:
常用 Berkeley Sockets API 一览表
学习这些 Socket API 的时候,不是让你单纯地记忆这些函数的参数,而是掌握每一个函数的重难点。
例如:
-
如何将一个 socket 设置成非阻塞模式
-
阻塞模式下,send 和 recv 函数行为是什么样子的?非阻塞模式下 send/recv 的返回值分别是什么?
-
客户端发起连接时,如何主动指定通过本地某个端口号去连接?bind 函数如果端口号设置为 0 是什么行为?
-
listen 函数的 backlog 参数用途是什么?
-
如何实现异步的 connect 函数?
-
accept 函数调用时,三次握手是否已经完成?
-
如何实现半关闭状态?
-
nagle 算法的用途是什么?
-
select 函数的第一个参数怎么设置?select 函数的超时参数如果设置为 NULL 是什么行为?
接着要重点学习下常用的网络模型:
-
Windows 上常用的网络模型有 select、WSAEventSelect、WSAAsyncSelect、完成端口模型;
-
Linux 上常用的网络模型 select、poll、epoll,epoll 需要重点关注的是水平模式和边缘模式。
当然,也建议一定要理解,不要死记硬背。C++ 的同学来面试的时候,我会给他们准备如下面试题:
-
epoll 边缘模式下,某次读取了某个 socket 上的部分数据,下次是否会出发读事件?如果此时又来了一个字节的新数据,是否会触发读事件?
-
epoll 边缘模式建议尽量一次把数据读完,怎样判断当前数据已经读完?
-
epoll 边缘模式下,对于写事件应该如何处理?
接着还要熟悉 TCP 协议的流式特性,如何解决粘包问题;还要掌握常见的网络协议格式,像 HTTP、FTP、POP3/SMTP/WebSocket协议的格式都建议熟练掌握。
以 HTTP 协议为例,HTTP 协议包的格式是什么样的,包头和包体如何分界的,GET 与 POST 请求的数据分别放在 HTTP 包的什么位置,如果放在包体中,如何知道包体的数据有多长。
推荐视频
C/C++网络编程,最新筛选精读视频,网络编程进阶必看(tcp、udp、epoll、网络协议栈、websocket、dpdk、网络穿透、reactor...)https://www.bilibili.com/video/BV1WG4y1g7H9/
7.3 学习常用网络命令
学习了常用的网络命令,可以用来排查网络故障与定位问题,反过来,也可以加深对网络理论知识的理解,建议掌握以下命令:ifconfig、ping、telnet、netstat、lsof、nc、curl、tcpdump。
掌握了这些命令要做到学以致用,例如现在某个服务器连接不上,如何使用这些命令判断是自己网络的问题还是目标主机的问题;开发了一个服务器程序,手头上没有可用的客户端,如何使用 nc 命令模拟一个;或者反过来,开发了一个客户端程序,如果用 nc 模拟一个服务器端用于测试。
C++ 网络编程方面的实战书来,我推荐韩国人尹圣雨写的这本《TCP/IP 网络编程》,这本书也适合无任何 Socket API 编程经验的小白,这本书涵盖从基础的 Socket API 到高级的 IO 网络模型,有非常详细和生动的例子。
等你有了一定的 C++ 网络编程以后(熟练使用常见 Socket API),你可以看看游双的《Linux 高性能服务器编程》(没错,还是这本书),这本书能让你写出完整的 C++ 网络项目来。
8. 第八阶段 学习数据库
如果你想系统地掌握数据库常用的知识点,一定不要以网上各种散乱的文章为重点学习材料,理由有二:
-
网上的资料碎片化比较严重,对于新人来说,可能会造成盲人摸象的感觉,无法形成成体系的技术认知;
-
网上的很多数据库文章都是对诸如《MySQL技术内幕》《高性能 MYSQL》的二次理解和加工,很多文章的内容对原有数据库知识理解不到位、甚至理解出错。
学习 MYSQL 数据库,建议方法:
-
找几本权威的数据库图书系统地学习一下,当然可以选择你感兴趣的部分,常用的数据库知识并不多;
-
自己安装一个数据库进行操作、实践。
例如,我在我的主机上安装了 MYSQL,我就可以这么练习:
Last login: Tue Jul 6 10:50:02 2021 from 106.26.160.131
Welcome to Alibaba Cloud Elastic Compute Service !
[root@myaliyun ~]# mysql -uroot -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 3550
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> show database
-> ;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'database' at line 1
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| flamingo |
| mysql |
| performance_schema |
| teamtalk |
| test |
+--------------------+
6 rows in set (0.01 sec)
MariaDB [(none)]> use flamingo;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [flamingo]> show tables;
+---------------------+
| Tables_in_flamingo |
+---------------------+
| t_chatmsg |
| t_user |
| t_user_relationship |
+---------------------+
3 rows in set (0.00 sec)
MariaDB [flamingo]> desc t_chatmsg;
+---------------+-------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+-------------------+-----------------------------+
| f_create_time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| f_id | bigint(20) | NO | PRI | NULL | auto_increment |
| f_msgcontent | blob | NO | | NULL | |
| f_remark | varchar(64) | YES | | NULL | |
| f_senderid | bigint(20) | NO | | NULL | |
| f_targetid | bigint(20) | NO | | NULL | |
+---------------+-------------+------+-----+-------------------+-----------------------------+
6 rows in set (0.00 sec)
MariaDB [flamingo]> select * from t_chatmsg limit 5;
Empty set (0.00 sec)
MariaDB [flamingo]>
数据库需要掌握的基础知识有:
(1)熟悉基本 SQL 操作 包括增删改查(insert、delete、update、select语句),排序 order,条件查询(where 子语句),限制查询结果数量(LIMIT语句)等
(2)稍微高级一点的 SQL 操作(如 Group by,in,join,left join,多表联合查询,别名的使用,select 子语句等)
(3)索引的概念、索引的原理、索引的创建技巧
(4)数据库本身的操作,建库建表,数据的导入导出
(5)数据库用户权限控制(权限机制)
(6)MySQL的两种数据库引擎的区别
(7)SQL 优化技巧
以上属于对开发的基本的数据库知识要求,你可以找一本相关入门级的数据库图书推荐:
-
《MySQL技术内幕(第5版)》
高级开发除了以上要求还要熟悉高可用 MySQL、主从同步、读写分离、分表分库等技术,这些技术的细节一定要清楚,它们是你成为技术专家或者高级架构的必备知识。我们在实际面试时,在讨论高可用服务服务方案时,很多面试者也会和我们讨论到这些技术,但是不少面试者只知道这些技术的大致思想,细节往往说不清楚,细节不会就意味着你的高可用方案无法落地,企业需要可以落地的方案。
这些技术我首推《高性能 MySQL》这本书,想成为高级开发者一定要通读的,另外还有两本非常好的图书也推荐一下:一本是《MySQL 排错指南》,读完这本书以后,你会对整个“数据库世界”充满了清晰的认识;另外一本是《数据库索引设计与优化》,这本书读起来非常舒服,尤其是对于喜欢算法和数据结构的同学来说。
-
《高性能 MySQL》
-
《MySQL 排错指南》
-
《数据库索引设计与优化》
推荐视频
关于中间件(mysql、redis、nginx),你必须知道的技术_哔哩哔https://www.bilibili.com/video/BV1oq4y1t77N/
9 学习代码规范与培养良好代码风格
在你学习的过程中,请一定要认真对待自己每一个变量名、函数名,养成良好的代码习惯。我学生时代花了大量时间去学习一些教人写出优美风格的代码书籍、资料、源码,在你还是个小白的时候,要认真精读一些优秀代码,不仅要学习它们的整体设计思路,还要学习它们的代码风格和细节。这里推荐《程序设计实践》《代码整洁之道》这两本书,特别是《程序设计实践》,强烈建议学生朋友看一下,能大幅度地提高你实际编码的技巧和编码风格。
10. 第十阶段 学习更多
经过前面九个阶段的学习,你已经是一个高级开发了,如果想进一步学习,需要将业务和技术结合起来,从业务的角度思考业务。
用一张图来看下:
上图中染色的部分是校招的基本要求,除了虚线框中的部分可以在较短的几年内掌握,剩下像编译原理、设计模式、数据库等需要长期的专研和总结,从熟练工到融汇贯通阶段已经与具体编程语言无关,一般要掌握:
10.1 学习高可用与容灾容错
服务都是人开发的,既然是人开发的,必然有宕机的可能性,当然宕机的原因可能是程序自身 bug,也可能是物理故障(断电、磁盘损坏等等),作为开发人员,针对不同的业务场景,我们没法做到服务 100% 可能,至少让其尽量可用,八仙过海各显神通。在宕机时如何尽量不影响业务、如何尽量快速恢复、如何保证数据和业务状态不丢失等等。这当然有一定的固定套路,例如主从、主备,当然固定的套路不是万能的,尤其是对于一些有状态要求的服务,这需要不断的磨练与自我总结。
10.2 学习分布式
分布式你需要掌握基本的分布式理论和原理,常见的分布式算法,然后是分布式系统设计的初衷和技巧,在实际并发量高的业务中,如何利用分布式解决高可用和访问效率问题。
10.3 学习 RPC
很多人都听说过这个词,在面试时也可以说出来个大概,但是当问到 RPC 技术解决的核心问题是什么就说不清楚了。当然,学习 RPC,我们还要考虑协议的设计(协议格式、序列化与反序列化、兼容性问题)、网络连接的重试、接口 stub 的设计等等。
10.4 学习消息中间件
目前除了自己公司自研的消息中间件,主流的有 Kafka、RabbitMQ、RocketMQ,如果想学习,建议选择其中一种深入学习一下,要掌握消息中间件的用途、选举策略、保序策略、重试策略、高可用策略等。
10.5 学习缓存
缓存的设计是一个很大的方面,个人觉得与其说这是一种设计思想而非单纯的某个缓存服务。当然,老生常谈的有缓存雪崩、缓存穿透、缓存击穿的解决思路。当然,以缓存为代表的服务是 Redis,Redis 的常用数据类型、适用场景、持久化、主从复制、哨兵与集群,这些建议你掌握,如果你从来没机会吃猪肉,那就看看猪跑吧,一些技术书籍和项目案例都有 Redis 的用途说明。
10.6 学习数据库高级知识
包括 SQL 调优、数据库调优、分表分库、主从同步等等。这个在前面介绍过了,不再重复。
11. 总结
最后,想说的是,成为技术高手不是一朝一夕的事情,既要相关工作经验的积累,也需要个人勤奋的努力和不断总结,才能达到融会贯通阶段。当然,兴趣是最好的老师。