计算机网络知识复习-(1)


1. 讲讲TCP/IP网络模型

首先TCP/IP网络模型一共分为四层,分别是应用层传输层网络层网络接口层

这与OSI的七层标准和描述工作原理的五层模型是不同的

OSI的七层模型分别是应用层、表示层、会话层、传输层、网络层、数据链路层、物理层

而讲述工作原理的五层模型分别是应用层、传输层、网络层、数据链路层、物理层

每一层所使用的协议栈都是不同的,通常来说,每一层的协议层都依赖于底层提供的服务,在层与层的交界点存在着一个叫做Access Point的地方,这个地方,就是底层向上层提供服务的服务访问点

2.讲讲应用层的作用

应用层位于TCP/IP网络模型的最顶层,是最高级的服务,当两个不同设备的应用需要进行通信的时候,应用就将准备好的分组加上应用层的首部,发送到下一层,然后交给传输层进行相关的封装

应用层的功能可以简述为调用传输层的TCP/UDP协议,根据用户的需求以及协议,封装相关的数组,将数据进行传输

典型的应用层协议有HTTP/FTP/SFTP/Telnet/DNS/SMTP

由于应用层是面向用户工作的,因此应用层是工作在操作系统的用户态,而应用层以下的是工作在操作系统的内核态的

3.讲讲传输层的作用

传输层是为应用层提供传输支持的,它属于面向通信部分的最高层,同时也是用户功能的最底层

为什么需要传输层?

这是因为网络层提供的服务是不可靠的服务,因此我们需要通过传输层的TCP协议来保证数据的可靠传输。

同时网络层在进行分组转发的时候,其传输节点单位是不同的主机,但是实际上,在操作系统中,发起数据的传输的实体实际上是进程,因此传输层在此还承担了分用/复用的功能

所谓分用,就是指接收来自网络层的数据之后,它会根据传输层的信息,将不同的数据分发到操作系统中不同的进程,这一点是通过端口来实现的

所谓复用,就是指接收来自应用层的数据之后,它会根据应用层的信息,将数据按照一定的协议等进行封装后,以相同的传输层协议进行数据的传输。

传输层中有两个主要的协议

TCP:全称是传输控制协议,大部分的应用都是使用的TCP传输层协议,比如说HTTP应用层协议,TCP相比起UDP比较复杂,比如流量控制、超时重传、拥塞控制机制等,这些都是为了实现数据的可靠传输,TCP的核心是滑动窗口协议

UDP:全称是用户数据报协议,它实现的不是面向连接的,因此不能够实现数据的可靠传输,它只负责发送数据包而不保证数据能否到达对方,因此它的实时性是更强的。

如果要实现UDP的可靠传输,那么只需要在更高层的应用层应用TCP的相关特性即可

应用层需要传输的数据可能会非常大,因此必须对TCP报文进行分段处理,一般在达到一个最大报文段MSS之后就会对数据进行分段处理,这样的话即使数据在中途丢失,只需要重新发送分块而不需要重新发送整个数据包

当接收方接收数据的时候,传输层需要将数据包分发给不同的应用,这是基于端口进行实现的,传输层的报文首部会携带端口,当解析完毕之后就可以分发到对应的端口了

4. 讲讲网络层的作用

网络层的功能实际上可以分为:路由选择分组转发

其中路由选择可以分为域内路由选择协议(RIP或者OSPF)和域间路由选择协议(BGP)

其核心协议是IP协议,它在传输的时候是这样工作的,它会将上层传输层的报文拿到,并且封装网络层的首部信息,注意,当IP报文很大的时候,也会进行分片,而依据是MTU,这个是在数据链路层规定的,最终得到一个合适大小的报文大小,开始发送

那么如果要将数据从一台主机发送到另一台主机,一种情况是局域网内通信,一种情况是联网通信,这两种情况都是基于IP地址进行通信的,我们先来理解比较复杂的联网通信,联网通信分为两步,找到目标网络所在路由器,将分组发送到目标路由器,然后目标路由器将数据发送到其局域网内部的主机上(这一步就是局域网内通信)

IP地址分为两部分,一部分是主机号,一部分是网络号,可以通过子网掩码来确定某一台主机是属于哪一个网络的

为什么需要子网掩码,这是因为IP地址有限,而通常又会搭建大型的局域网,因此提出了子网掩码来表示一个局域网,从前是使用A/B/C/D四类的地址来进行网络类型的划分的,然而这种方式不灵活,后面改用CIDR,就非常灵活,能够根据网络内的主机数合理分配IP

5. 讲讲网络接口层的作用

网络接口层对标的是讲述原理的五层中的数据链路层部分,其功能是借助于物理设备,在同一个网络内部传输数据

首先我们要知道,IP地址实际上是软件分配的,而真正的硬件的地址叫做MAC地址,这个MAC地址能够区别出世界上任何一台物理设备,因此在局域网内通信的时候,需要将IP地址转化为MAC地址,这个协议叫做ARP协议

ARP协议工作的流程是这样的:

首先在局域网内如果要数据传输,那么首先它会先将IP地址解析为MAC地址,这个过程通常要借助于设备上的ARP Cache,它本质上就是一个哈希表,当它能够通过IP地址找到MAC地址的时候,就会在MAC帧上封装对应的目标MAC地址,然后发送过去

而如果Cache中没有对应的MAC地址的时候,就会触发学习,它会发送一个广播,当有设备的IP地址对得上的话,就会发送回答,然后这时候的发送设备就会记录这个IP->MAC的映射,然后自此以后就可以直接封装MAC帧了

6. 从你输入一个网址到页面的显示,都发生了什么?

在这个过程中,输入就是网址的URL,输出就是服务器给我们的响应

第一步:解析URL

首先浏览器要做的第一个工作就是要对URL进行解析,从而生成给Web服务器的请求信息

关于URL的组成 http://webServer/index/index.html

http:这是URL的开头,表示访问数据的协议

//:分割符

webServer服务器:分割符后就是web服务器的名称,要么是域名,要么是IP地址

当设定了欢迎页时,后面的这些地址信息可以省略掉,一般是根目录下的index.html

/:分割符

index:目录名

index.html:文件名

第二步:生产HTTP信息

对URL进行解析之后,我们得到了两个有用的信息所使用的协议Web服务器和我们想要访问的资源路径以及还有一些用户附加的参数等

接下来就是根据这些解析出来的数据,封装报文,报文分为两种,分别是请求报文响应报文

请求报文,请求报文可以粗略分为请求行+首部+包体

请求行 = {方法+URL+版本}

首部是一些键值对,用来传输一些相关数据,比如cookie或者是否keep-alive

其中首部可以分为请求行,请求头,报文段就是请求体了,一般来说,首部和请求体之间有一个空行进行分割

而请求可以分为GET请求和POST请求,其中GET请求一般用来向服务器请求数据,参数在url中携带,而POST请求一般用来向服务器发送数据,因此是危险的,通常会将数据封装到包体中。

响应报文:响应报文可以粗略分为状态行+首部+包体

状态行 = {版本+状态码+短语}

首部,也是一些键值对,用来携带一些服务器信息,比如响应的时间等

第三步:解析IP地址

由于两台主机之间需要通信,那么必须借助于网络层的IP协议,而我们目前得到的url中的web服务器地址是一个域名,因此必须通过DNS解析后才能得到IP地址

第四步:交付下层

得到了IP地址,那么这个数据报就可以在网络层进行传输了,协议栈的内部分为几个部分,分别是应用程序层操作系统层驱动程序层硬件层,上层应用会向下层委托工作,

在这一步中,应用程序通过调用socket来委托协议栈工作,socket本质上是对传输层协议的抽象,因此会先通过TCP协议,将应用程序交付下来的数据封装为TCP/UDP报文,然后将此报文交付到网络层,通过网络层,将分组转发到对应的主机去,在这个网络层中,还会有两个辅助协议,其中为IP层提供报告的是ICMP协议,ARP协议是工作在较低层,它用来完成软件地址到硬件地址的转化。

而后将数据包交付到驱动程序,驱动程序负责给网卡发送指令,而网卡则是完成实际的I/O操作

第五步:基于TCP实现可靠传输

在TCP传输数据之前,必须要完成三次握手,初始时,服务端和客户端处于CLOSED状态,当服务端开始监听请求的时候,此时就进入到了LISTEN状态,该状态下就能够处理来自客户端的请求了

首先客户端会发送第一个报文,该报文的标志位SYN = 1,代表进入SYN-SENT状态

然后如果服务端接收到了第一个报文并且做出响应,该报文的标志位为SYN=1,并且携带ACK=1的标志,表示收到了来自客户端的请求连接报文,进入了SYN_RCVD的状态

然后此时客户端连接建立,进入ESTABLISHED,然后发送第三个报文,该报文撤销了SYN=1,是对第二个报文的ACK,当服务端接收到这个报文时,就说明连接成功建立,进入ESTABLISHED状态

注意,在连接建立的过程中,实际上也是要依赖于底层的网络层传输的

第六步:交付数据到网络层

网络层接收到来自于传输层的数据,然后封装源IP地址和目的IP地址到首部,然后执行网络层的传输,然后这时候会先检测数据是否在同一个局域网,假设不在同一个局域网,那么就通过主机上的默认网关,发送到路由器上,由路由器完成路由选择

路由选择的过程如下:首先通过目的IP地址和子网掩码进行目的主机所在的网段,这个过程要通过最长前缀匹配原则进行路由选择,也就是子网掩码越长的匹配优先级高,当所有路由都不匹配的时候,将通过默认路由转发出去,将寻址任务交给下一个路由器

路由器与路由器之间的寻址非常复杂,一般来说有静态路由法,这种方法是直接写入路由器的路由表,便于寻址,还有的是动态路由,有OSPF和RIP,他们能够动态地维护路由表

通过路由选择协议找到对应的路径后,将分组传输到目标网段的路由器上

第七步:在局域网内传输数据

局域网内的数据传输,一般要通过以下步骤

第一步,先将目的地址与本机的所在网络地址进行比较,如果是同一个网络,那么就直接通过网络适配器中的ARP Cache查找IP地址所对应的MAC地址,然后通过数据链路层设备发送MAC帧到目标设备

然后请求数据就会到达目标主机

到达目标主机后,需要进行数据的拆包,一直拆包到传输层,此时进行数据的分发,根据TCP首部的目的端口,将数据发送到对应的端口进行使用,然后应用层接收到请求,准备好数据后,通过已经建立好的TCP连接持续发送数据

直到全部接收完毕,这期间双方的会维护一个发送窗口实现可靠传输

第八步:传输结束,关闭连接

传输层要执行四报文挥手

当数据传送完成后,客户端向服务端第一个挥手报文,内容将FIN = 1,请求关闭连接,此时进入FIN-WAIT1状态

然后服务端接收到这个报文后,发送第二个挥手报文,内容是对上一个挥手报文的确认,然后此时客户端进入FIN-WAIT2状态,等待服务端发送完剩余的数据,服务端进入CLOSE-WAIT状态

然后服务端如果有数据的话就会把剩余的数据发送过来,发送完毕后,会进入到LAST-ACK会发送第三个挥手报文,代表着服务端不会再发送任何数据了,进入

当客户端接收到第三个挥手报文的时候,此时就会发送最终确认,客户端进入TIME-WAIT,同时发送第四个挥手报文,进入TIME-WAIT状态,需要等待2MSL

7. 说一说Linux网络协议栈

Linux的网络协议栈主要还是依赖于四层模型中提供的各层协议,可以这样描述:

首先Linux用户程序发起网络传输请求,此时会发起一个系统调用,然而此时并不是直接调用TCP/UDP等传输层协议,在这里它做了一个封装,用socket这样一个套接字来描述一个网络连接的数据,应用程序从通过调用socket提供的接口,完成数据的提取,在这个过程中,TCP/UDP以及下层的IP协议对用户来说都是无感的

那么socket的底层就替用户完成了网络传输的具体工作,它通过发起TCP/UDP请求,来和对等端进行网络数据通信,在更底层的网络层,通过IP协议完成路由选择,分组转发功能,通过ICMP协议完成网络传输状态报告,在更底层的网络接口层完成ARP协议负责的软件地址到硬件的转换,最终通过物理设备之间的数据交换完成数据的通信

总而言之,就是应用程序通过系统调用,来与socket层进行数据的交互,socket的下层就是传输层,网络层,网络接口层,最终到最基础的物理设备,网卡驱动程序和硬件网卡设备

8. 说说在Linux下数据包是怎么接收的吧?

这个问题需要从网络适配器,也就是我们说的网卡接收到第一个数据包开始讲起

我们知道网络数据包的发送和接收都是属于I/O的,因此这些I/O操作都将会导致操作系统的中断,在最初的设计中,对于收到一个数据包来说,它会通过DMA技术,所谓DMA技术就是直接内存写入技术,它通过窃取总线周期,在这些空闲的时间段内,将数据包写入到内存中,而不会导致线程的阻塞,然后当数据包写入内存完毕后,网络适配器就该通知CPU了。

这时候有一种最简单的方式,就是向CPU发起中断,只有当CPU处理完数据后,网卡才可以接着向下处理别的数据。

这显然是不利于提高吞吐量的

还有一种方式,叫做NAPI,它是基于轮询+软中断实现的,它的实现机制是:当网卡发过来一个硬中断的时候,这时候CPU会执行两个操作

  • 首先,它会暂时屏蔽掉这个中断,然后以信号通知网卡,告知其可以继续写入数据
  • 然后,它会发起一个软中断,软中断的线程去处理这个中断

如此一来,数据包就能够以高吞吐量的方式写入内存了,然后处理线程会从内存中提取数据包,通过网络协议栈进行处理

  • 第一步:首先经过网卡接口层,在一层中进行差错检测,如果有错则丢弃,没有错则找出上一层的协议类型,然后进行上层交付
  • 第二步:到达网络层,通过IP来判断这个数据包是否需要转发,如果需要转发,则根据路由表进行转发,否则的话继续拆包。
  • 第三步:通过协议类型判断其是TCP类型还是UDP类型,去掉IP头,到达传输层,然后根据[源主机IP,源端口,目的地址IP,目的端口],发送数据到对应端口,然后顶层程序通过调用socket的方式提取数据即可。

9. 再讲讲Linux下数据包是怎么发送的吧

这个问题从协议栈的处理角度来说,是一个逆过程,但是在操作系统完成操作的过程中,有很大的区别

首先,要完成的工作是通过操作系统的调用,将用户空间的数据封装为对方机器协议栈所能处理的数据包

此时用户程序已经准备好了数据,然后此时系统申请一个sk_buff的缓冲,这个缓冲的作用是用来存储用户数据的,将用户空间的数据拷贝到sk_buff中,然后将其加入到发送缓冲区中

接着,网络协议栈从socket中取出数据,如果传输层使用的是TCP协议的话,那么这里会做一个拷贝,这个是因为TCP实现的是可靠传输,其中所实现的滑动窗口中规定,如果一个序号所对应的数据包没有被ACK,那么窗口就不能够删除这个数据,所以的话它这里会产生一个拷贝,实际上我们发送出去的那个数据包就是这个原始的sk_buff的一个拷贝,然后通过下层网络接口层,封装对方的IP地址,填充IP头,然后再到网络接口层,给它加上帧头和帧尾,然后完成以上所有的网络协议栈封装之后,就可以将这个sk_buff挂载到RingBuffer里面了

当网卡将sk_buff发送出去之后,还要完成收尾工作,也就是将内存中的sk_buff拷贝删除掉,然后再将RingBuffer里面有关sk_buff的挂载信息给删除掉

然后当这个机器收到关于sk_buff的ACK之后,就会删除掉原始的sk_buff

10. 发送数据包最多有几次拷贝操作?

我认为是三次

第一次,从用户空间中拷贝数据到sk_buff中进行保存

第二次,检测是否需要分包、分片,如果需要,则会申请新的sk_buff,然后将原始数据拷贝到这些新的sk_buff

第三次,如果使用TCP协议,原始数据需要保留的情况下,会发送一次原始的数据的拷贝


文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录