计算机网络有一个显著的特点,就是不仅需要背诵,还需要将原理烂熟于胸。
我们都知道网络是分层的,每一层有每一层的沟通方式。
第一个问题:TCP在进行三次握手的时候,IP层和MAC层对应有什么操作?
学习第三层协议的时候会提到,IP协议里面包含源IP地址和目标IP地址。还会学到路由协议。路由就像中转站,从原始地址A到目标地址D,中间经过两个中转站A->B->C->D,是通过路由转发的。
那么第二个问题:A知道自己的下一个中转站是B,那么A发出来的包,应该把B的IP地址放在哪里?同理,B知道下一个中转站是C,那从B发出来的包应该把C的IP地址放在哪里?如果放在IP协议的目标地址,那么包到了中转站怎么知道最终目的地址是D呢?
第三个问题:你一定听过二层设备、三层设备。如果发送一个HTTP的包,这是七层的,那是不是不需要经过二次设备呢?或者说,二层设备处理的包有没有HTTP层的内容呢?
第四个问题:从你的电脑,通过SSH登录到公有云主机里面,都需要经历哪些过程?你打开一个电商网站,都需要经历哪些过程?
尽管很多人对每一层都很熟悉,但是只是却串不起来。
因为,复杂的程序都要分层。
理解计算机网络的概念,一个很好的角度是,想象网络包是一段内存,是有格式的。同时,想象自己是处理网络包的程序,这个程序可以跑在电脑上,服务器上、交换机上、路由器上。想象自己有很多的网口,从某个口拿进来一个网络包,用程序处理一下,再从另一个包发出去。网络包的格式很复杂,程序也很复杂。复杂的程序都要分层,这是程序设计的要求,让每一层专注做本层的事情。
想象“你”这个程序的工作过程。
当一个网络包从一个网口经过的时候,你看到了,首先看看要不要请进来,处理一把。有的网口配置了混杂模式,凡是经过的,全部拿进来。
拿进来之后,就要交给一段程序处理。于是,你调用process_layer2(buffer)。当然这个函数是假的,但你知道一定存在这样一个处理二层包的函数。这个函数摘掉二层的头,看看根据头里面的内容做什么操作。
假如你发现这个包的MAC地址和自己的一样,那么说明这个包是发给你的,于是你调用process_layer3(buffer)。这个时候,buffer里面已经没有二层的头了,上一个函数已经拿掉了。在这个函数里摘掉三层的头,看看到底是发给自己的,还是希望转发出去的。
如果IP地址不是自己的,那就应该转发出去;如果IP地址是自己的,那就是发给自己的。
拿掉三层的头,进行下一层的处理。根据IP头里面的标识,决定调用process_tcp(buffer),或者调用process_udp(buffer)。
假设这个地址是TCP的,则调用process_tcp(buffer)。这个时候buffer里面已经去掉了三层的头,需要查看四层的TCP头,看这个是一个发起还是一个应答,还是一个正常的数据包。如果是发起或应答包,接下来可能要发送一个回复包;如果是一个正常的数据包,就需要交给上层了。
如果是一个网络包处理程序,则交给应用去处理。交给哪个应用由端口号区分,不同的应用会监听不同的端口号。如果发现浏览器在监听这个端口,就交给浏览器。至于浏览器怎么处理,和你没有关系。
浏览器解析HTML,显示出页面来。用户看到页面,然后点击鼠标,点击的动作被浏览器捕获。浏览器就知道要发起另一个HTTP请求,于是使用端口号将请求发给你。
于是你调用send_tcp(buffer)。buffer里面是HTTP请求的内容。这个函数里面加一个TCP的头,记录下源端口号。浏览器会给你目的端口号。
然后后调用send_layer3(buffer)。buffer里面已经有了HTTP的头和内容,以及TCP的头。在这个函数里面加一个IP的头,记录下源IP地址和目标IP地址。
然后调用send_layer2(buffer)。buffer里面已经有了HTTP的头和内容、TCP的头,以及IP的头。这个函数里面要再加一个MAC的头,记录下源MAC地址和目标MAC地址。目前还不知道目标的MAC地址,需要通过一定的协议处理,找到目标MAC地址。
只要buffer里面的内容完整,就可以从网口发出去了,你作为一个程序的任务就完成了。
回到一开始的问题:TCP在三次握手的时候,IP层和MAC层在做什么呢?
当然是TCP每发送一个消息,IP层和MAC的所有机制都要运行一遍。只要是在网络上的包,都是完整的。可以有下层没上层,但绝不可能有上层没下层。
对于TCP协议来说,只要想发出去包就要有IP层和MAC层,不然发不出去。
理解网络协议工作模式的两个窍门:
两个思考题:
1. 经常有人把不同的网络分层比喻成公司的不同级别,下层比作员工,上层比作经理,你有更恰当的比喻吗?
2. 学习网络协议,IP这个概念是最基本的,你知道如何查看IP地址吗?
PS:本文是极客时间,刘超老师《趣谈网络协议》的讲义摘录。