有读者问我:轩辕,你是怎么学计算机网络的?
鸽了好久,今天得空聊聊这个话题。
轩辕是通信工程专业,计算机网络通信自然是必学内容。
我猜,绝大多数同学的计算机网络知识,估计都是在学生时代,抱着谢希仁那本厚厚的《计算机网络》课本,老师念着上个世纪就传承至今的教案PPT得来的。
如果运气好,老师讲的不错,还学的进去。
如果运气不好,老师只是一个PPT播放机的话,那就···
很不幸,我就是运气不好的那种。
老师讲了一大堆协议啊,局域网、广域网、网络设备啥的,我却听着听着经常就神游太虚了。
一次偶然,发现隔壁班的计算机网络是当初教计算机二级的老师在上课,这位老师的讲课风格一直是我非常喜欢的,于是我和两个小伙伴就一起溜进去蹭课,这一蹭不要紧,一下就上了瘾。
这位老师风格独立,根本不用学校发的教材,而是自己编写了一套PPT,从最底层的原理讲起,从通信的编码校验,到局域网的802.3、802.4、802.5等技术演进,用生动有趣到生活实例告诉我们什么是CSMA/CD,听得我们如痴如醉。我现在写的很多故事性的文章,一定程度上都有这位老师的影响。
在我们几个的口口相传下,我们班在上计算机网络课时,门可罗雀,而隔壁班人却越来越多,不知道我们的计算机网络老师看到后心里有何感想。
果然,老师的力量还是很大的,一下子就开了窍似的,学起来简单多了,期末考试轻松拿下100分。
我的经历
期末考试结束后就是暑假,我进入学校的网络安全实验室了,进入之后的第一个任务,也是事关我们能否留下来的考核题目来了:编写一个HTTP流量还原的软件。
程序要求:输入一个从wireshark等抓包软件导出的pcap文件,输出这其中所有传输的HTTP内容,包括HTML、CSS、JS、JPEG、PNG、GZIP等等内容。
包括我在内,同批次进入实验室的总共有5个人,大家各自负责不同的协议流量还原,有FTP、SMTP、HTTP、IMAP、POP3,我算运气好的,因为HTTP相对来说是最熟悉的了。
那时刚刚大一暑假,才刚刚学完C语言,虽然已经提前自学了C++,但面临这个题目还是慌了。
最大的问题就是,网络数据包只在课本里学过报文格式,我也没见过真正的数据包长啥样,也不知道在pcap文件里怎么存储的,更不知道如何把HTTP传输的数据给还原出来了。
总之,就是当时对网络流量的认识还停留在类似上面这样的图上,至于数据包长啥样则完全没概念。
有一天晚上,实验室的老师安排了高一届的师兄们给我们讲解了如何抓包,怎么查看网络通信数据。
那是我第一次在抓包软件下看到了网络中数据流量的真实样子,触动特别大,平时躺在书本上的报文格式,现在活生生的出现在了眼前,每一个字节,甚至每一个比特的意义都在抓包软件下看的清清楚楚,原来,网络是可以看到的!
在抓包软件下,网络的分层不再是一个静态的分层模型图,而是看得到的一层又一层的报文头,从链路层的以太网协议,到网络层的IP协议,再到老大难的TCP头部,再到上面的应用层协议,那一串二进制比特流数据,用一棵协议树的形式对应了起来。
那几天,我们都在集中学习抓包,看着自己浏览的网页数据,最后都能在抓包软件中找到它,我对计算机网络的理解开始变得立体起来。
抓包学的差不多,就要开始编写程序完成任务了。
在C/C++语言中,为了处理报文数据,就会定义各种各有的协议结构体,这一来,又进一步强化了对每个字段的理解,因为它不再是书本上一个简单的字段名字,它变成了我代码结构体中一个实实在在存在的成员变量。
- typedef struct _ip_hdr
- {
- #if LITTLE_ENDIAN
- unsigned char ihl:4; //首部长度
- unsigned char version:4, //版本
- #else
- unsigned char version:4, //版本
- unsigned char ihl:4; //首部长度
- #endif
- unsigned char tos; //服务类型
- unsigned short tot_len; //总长度
- unsigned short id; //标志
- unsigned short frag_off; //分片偏移
- unsigned char ttl; //生存时间
- unsigned char protocol; //协议
- unsigned short chk_sum; //检验和
- struct in_addr srcaddr; //源IP地址
- struct in_addr dstaddr; //目的IP地址
- }ip_hdr;
这里插一句,以前学C语言,学到联合体union、位域这些东西时一直不知道怎么用以及有啥用,直到去处理解析这些协议头数据的时候才发现:哇靠!真香!
说回我的程序,我的程序分为了两个阶段,第一步,先把pcap中存储的数据包都展示出来,这一步主要是文件格式处理和数据包的分层解析。
第二步,识别HTTP会话,提取传输的内容。
这第一步倒还好,熟悉了文件格式和报文分层的格式后,循环遍历pcap文件内容,挨个分层解析协议即可。
但是这个第二步就有些困难了,最重要的就在于HTTP的传输层是TCP,TCP里面涉及到超时重传、乱序等一些复杂的情况,要完整的合并一个会话,考虑到上面这些情况,就没那么容易了。
不过,困难亦是机遇,一直对计算机网络协议中的TCP这头拦路虎有些惧怕,这一次是时候跟它好好把话说清楚,道明白。
序列号SEQ和确认号ACK是TCP传输的基石,抓住这俩家伙,就能抓住TCP会话的脉络。
经过一阵研究摸索,总算写出了一套算法来进行会话流的重组,虽然现在回过头去看还是有很多考虑不足之处,但在当时已经能解决面临的问题。
通过编程来进行流重组的过程,对TCP的超时重传、拥塞控制、滑动窗口、数据乱序等细节有了完全不一样的理解。
以前只是从概念上记住理解,而现在是自己要从代码层面处理这一个个的场景,这个掌握的深度自然是不一样的。
差不多一个月后,暑假过了一半儿,我总算把这个程序写了出来,看着自己上网的内容被自己的软件完整的还原出来,心里那种感觉,别提多有成就感了。
那时候开始,我对网络中数据的传输从里到外到底如何在工作有了全新的认识。它不再是停留在课本上那一张张静态的报文格式图。
一点通而多点通,有时候一个关键的点弄通透了以后,学习其他相关问题就会有豁然开朗的感觉了。
知道了网络中的数据如何在传输,再回过头去看那些各种各样的网络协议就轻松多了。
这时候再把视角拔高一些,为什么网络协议要分层,每层的职责是什么,集线器跟交换机组网区别是什么,这些问题不用看书,自己就能回答上来了,它确实就该是那样子的!
方法总结
计算机网络这门课,属于计算机四大基础课程之一,无论是什么技术栈,只要从事计算机行业都得学。
而学习的方法和途径呢,我推荐的方法是看书学理论+实战相结合的方式。
第一个层次,看书+看视频。
虽然看书很是头疼,但基础知识最好还是得通过看书来获得。
看的时候呢可能会遇到各种各样的疑问和困难,这时候我建议先从整体把关,不必拘泥在某个字段上。先对计算机网络先有一个初步的认识,知道这大概是个什么东西,解决了什么问题。
有了初步的概念和大体的认识,再逐层细化。
推荐书目:
- 《TCP/IP协议详解》(卷一)
- 《网络是怎样连接的》
- 《图解TCP/IP》
如果实在是觉得看书学不进去,那我推荐你可以去看视频,这年头,视频学习资料到处都是,只要你肯花功夫,通过视频也能学好。
视频呢也分两种类型,一种是高校的公开课,你可以在网上找到一些计算机专业比较知名的学校,看看他们的公开课,比如清华大学、电子科技大学、上海交大等等。
这一类视频的特点是比较中规中矩,就像在大学里面上课一样,氛围感会更强一点,缺点是可能显得有些枯燥,不过毕竟是名校的资源,比较系统全面,更靠谱一些。四舍五入就相当于在这里上学了。
另外一种就是一些自媒体博主,或者一些机构推出的专栏课程。这一类相对更新一些,照顾到年轻人的口味,会用一些动画之类的方式来呈现,讲述的也更有趣一些。
按照套路,我是不是应该推荐几个放在这里?
但我没有。
我觉得吧,视频课程每个人的口味都不太一样,画面、PPT质量、老师的声音、语速、讲述风格等都有要求。
授人以鱼不如授人以渔,大家可以去B站、网易云课堂上面搜一下,这两类的视频都有许多,其中不乏高质量的视频,建议多去看几个比较比较,看看自己更喜欢哪一款。
第二个层次,抓包。
看书和视频,这些知识还只是静态的,纸上得来终觉浅,想要掌握扎实,就得学会抓包,自己亲自动手抓一抓网络中传输的数据包,看一下它们到底长什么样子,并通过抓包工具分析各个协议的各个字段的作用,把前面学来的理论知识实际用起来。
这里我列举一些可以关注的抓包场景:
- ping一个IP地址,抓包分析IP+ICMP
- ping一个域名,抓包分析UDP+DNS
- ping一个局域网IP,抓包分析ARP
- 禁用网卡重新启用,抓包分析DHCP
- 访问一个网站域名(非HTTPS),抓包分析TCP和HTTP
- 访问一个网站域名(HTTPS),抓包分析HTTPS
至于抓包工具选择,可以看看我的这篇文章:我抓了一个包,你不想看看?
而且,学会了抓包,也会在工作中排查问题大有帮助,实在是程序员必备技能!
这里再推荐两本抓包分析书籍:
就像书的标题一样,网络分析就这么简单!作者文笔出众,不是那种一板一眼的教科书,从实际工作中遇到的问题出发,引领你学习,很容易看进去。
第三个层次,编程。
达到第二个层次,对于大多数人已经足够了。但如果你想对计算机网络了解对更深一些,或者你的工作与网络紧密相关,那么写点代码绝对是不二之选。
那写点什么类型的代码好呢?
第一类是编写我上面说的那种网络流量数据分析软件,通过分析处理真实的数据包,实际处理每一层每一类协议的每个字段,哪怕你只是把数据包内容分层展示出来,那也是有非常大的帮助。
第二类就是编程来收包和发包。我们平常使用套接字编程,一般都是封装的应用层协议,如果你是学习应用层协议,用套接字就可以,比如你可以写一个简单的静态webserver,对HTTP协议进行封包解包。
而如果你想学习更底层协议的封包,比如TCP、UDP、ICMP、ARP、IP这些协议,那就得另谋他法,比如原始套接字,比如一些开源SDK等。
第三类,更进一步,可以尝试编写一些内核驱动程序,通过操作系统提供的接口,进行数据包的监控、拦截过滤与修改、通信阻断,实现一些有趣的功能,比如自己实现一个简单防火墙,开发一个进程通信监控软件等等。
再说几句
上面只是对于开发人员的一些建议,对于专业的网络工程师、运维会有所不同,可能还需要学习组网技术、交换机/路由配置、防火墙和网络安全等相关的知识。
本文转载自微信公众号「编程技术宇宙」,作者轩辕之风O。转载本文请联系编程技术宇宙公众号。