目录
4.4 ARP协议(Address Resolution Protocol)
4.5 RIP协议(Routing Information Protocol)
4.7 ICMP协议(Internet Control Message Protocol)
5.1 UDP协议(User Datagram Protocol)
5.2 TCP协议(Transmission Control Protocol)
6.3 DHCP协议(Dynamic Host Configuration Protocol,动态主机配置协议)
一、网络分层
1.1 OSI七层模型
由国际标准化组织提出的一种概念模型。该模型将通信系统中的数据流划分为七个层次,每个中间层为其上一层提供功能,其自身功能则由其下一层提供,第1层在底部。
第七层 应用层:提供为应用软件而设计的接口,以设置与另一应用软件之间的通信。
第六层 表示层:把数据转换为能与接收者的系统格式兼容并适合传输的格式。
第五层 会话层:负责在数据传输中设置和维护计算机网络中两台计算机之间的通信连接。对应主机进程,指本地主机与远程主机正在进行的会话
第四层 传输层:把传输表头(TH)加至数据以形成数据包。传输表头包含了所使用的协议等发送信息。
第三层 网络层:进行逻辑地址寻址,实现不同网络之间的路径选择。
第二层 数据链路层:负责网络寻址、错误侦测和改错。将比特组合成字节,进而组合成帧,用MAC地址访问介质,能发现错误但不能纠正。
第一层 物理层:建立、维护、断开物理连接。
1.2 TCP/IP 四层模型
OSI七层模型只是一种理论上的概念模型,并没有提供一个可以实现的方法,而只是描述了一些概念,并不一定就完全代表了实际情况。其实在实践中不用分的那么细致,OSI中的一些理论分层可以"合并"实现。实际情况使用的就是TCP/IP四层模型,其定义如下:
第四层 应用层:相当于组合了OSI七层模型中的会话层、表示层、应用层
第三层 传输层:同OSI七层模型中的传输层
第二层 网际层:同OSI七层模型中的网络层
第一层 网络访问(链接)层:相当于OSI七层模型中的物理层和数据链路层
1.3 五层模型
除了上面提到的理论上的七层模型和实际使用的四层模型,还有一个五层模型。这个五层模型结合了七层模型和四层模型,主要用于网络协议原理介绍,它与TCP/IP四层模型的区别就是将网络访问(链接)层分为了数据链路层和物理层。OSI七层模型、TCP/IP四层模型和五层模型对比如下:
接下来就以五层协议为标准进行总结。
二、物理层
物理层是模型中最低的一层,它确保原始数据可以在各种物理媒介上传播。所谓的媒介包括光纤、电缆或者电磁波等等,这些媒介可以传输物理信号,比如高电压、低电压。若用1表示高电压,0表示低电压,将数据转化为按照规范组合的0/1序列,就可以在物理媒介上传播了。对于接收设备,也需要接口能接受这些物理信号,将其重新转换为0/1序列,以完成数据的接收。
三、数据链路层
即连接层,在两个网络实体之间提供数据链路连接的创建、维持和释放管理,信息以帧为单位传输。所谓帧,就是一段0/1序列组合,其中有收信地址、送信地址、校验序列(探测错误)等等,其中的地址是MAC地址。帧中的数据往往符合更高层协议,供上层使用。数据链路层就像一个送货员,不会关心数据的具体内容。
此层中常见的协议有以太网、WiFi、帧中继等等,通过这些协议,我们可以建立一个局部网络(局域网),使得一个局域网中的两台计算机可以通信。
帧分为帧头、数据、帧尾,帧头和帧尾包含同步信息、收发地址信息、差错控制信息等,数据部分则包含网络层传下来的数据,比如IP数据包。
帧头包含一段被称为序言的0/1序列,开始会以一定的频率发送序言,接收设备要按照一定的频率接收才能做到不丢失信息。就像我们收听录音机之前,需要先调整接收频率,直到听清楚播报内容,这个过程叫做调频。在帧中,序言就是为了发送设备和接收设备频率一致,这个过程叫做时钟复原。时钟调整好之后,等待帧的起始信号(SFD,start frame delimiter,为固定值)。起始信号之后,还有帧的发送地址和目的地址,当然,这个地址是MAC地址。
关于数据部分,前面已经提过了,一般包含符合更高层协议的数据,但是由于数据有最小长度限制,所以尾部可能包含一部分0填充。
帧尾包含校验序列(FCS ,Frame Check Sequence),主要是为了校验数据是否发生错误。检测使用CRC(Cyclic Redundancy Check,循环冗余检查)算法:在一个n位二进制序列之后增加一个m位的二进制序列,生成长度为n+m的新二进制序列。这个m位的二进制序列可以称之为校验位,m位的校验位与n位的原数据之间存在一定的关联,如果原数据异常,就能通过校验位检测出来。
3.1 集线器和交换器
一台集线器或者交换器上有很多端口,每个端口都能连接一台设备。
-
集线器:一台设备将帧发送到集线器,集线器会将帧广播到其他所有端口,每台设备收到帧之后,检查帧的目标地址是不是本设备的MAC地址,如果不是则忽略该帧。也就是以广播的方式转送消息,所有设备都能收到其他设备发送的消息。存在的问题一个是安全性,当然可以加密消息;另外一个是不允许多路同时通信,如果两台设备同时向集线器发送消息,那么集线器会提醒发生冲突,设备上可以实现冲突检测算法,如果发生冲突,那么随机等待一段时间再发送。WiFi的工作方式与此类似,所以WiFi需要特别注重加密(WPA、WPA2)。
-
交换器:交换器记录了每个设备的MAC地址,当交换器收到帧之后,会根据帧的目的地址和本机存储的MAC地址记录,只将帧发送到对应的端口,进而准确发送到对应的设备。交换器允许多路同时通信。
四、网络层
数据链路层使得同一个局域网中的的计算机可以相互通信,但是也只限于同一个局域网。要想让一个局域网里的计算机和以太网上的另一台计算机通信,则需要一些其它手段。这就是网络层需要做的事儿:提供路由和寻址的功能,使两终端系统能够互连且决定最佳路径,并具有一定的拥塞控制和流量控制的能力。
在数据链路层的帧中,只有送信地址和收信地址(MAC地址),但是跨局域网通信至少需要四个地址(比如数据从一个计算机经过WiFi接口,以太网接口,再到另一个计算机),又由于数据链路层已经存在并且正在使用,不能随意对其更改,所以只能在数据内容上做文章:将目标地址、校验信息等写到数据内容开头,反正数据链路层也不关心具体的数据,这就是IP协议。网络层协议由IP协议规定和实现,所以网络层又称为IP层。
关于目标地址,IP协议需要的地址和数据链路层需要的地址不一样。数据链路层的地址是物理地址(MAC地址),相对应的,网络层使用的地址叫做IP地址。当设备连接网络,设备将被分配一个IP地址用作标识。通过IP地址,不同网络间的设备可以互相通讯,如果没有IP地址,我们将无法知道哪个设备是发送方,哪个是接收方。
大多数接入Internet的方式是把主机通过局域网组织在一起,然后再通过交换机或路由器等设备和 Internet 相连接。在同一个局域网络中的计算机不需要网络层,仅依靠数据链路层就可以通信,但是对于不同的网络之间相互通信则必须借助路由器等设备。
4.1 MAC地址和IP地址
两台设备进行通讯的前提就是知道双方的地址,而IP地址和MAC地址都是地址,那么仅仅依靠IP地址或者MAC地址能否完成路由呢?
随着网络接入设备越来越多,为了解决寻址的问题,网络结构被层次化构造,被划分为了很多个子网,在路由的时候,如果数据包的目的地在其他子网,那么只需要把数据包路由到该子网,剩下的工作交由子网内部处理,这极大的减少了路由器计算量。
MAC地址有48位,可以唯一表示一个网卡,是网络设备制造商生产时写在硬件内部的。而基于子网的这个结构,如果使用MAC地址进行以太网设备的寻址,那么路由器需要记住每个MAC地址所在的子网。但是理论上,MAC地址可以有2^48个,这个数据量需要占用的内存就不允许我们这样做,所以有了IP地址。(以下对于IP地址的描述都基于IPV4)。
IP地址由IP协议提供统一的地址格式。一个IP地址包含两个标识码:网络ID和主机ID。同一个局域网络上的所有设备都是用同一个网络ID,网络上的一个主机(包括路由器)有一个主机ID与其对应。IP地址(IPV4)是一个32位的二进制数,通常被分割为4个8位二进制数,一共4个字节,比如通过点分十进制表示格式为:123.324.213.23,其中每个部分都是对应8位二进制数的十进制形式。同时,Internet委员会定义了5种IP地址类型以适合不同容量的网络,即A类~E类。以C类IP地址为例:
一个C类IP地址的4段号码中,前三段为网络ID,第四段为主机ID,也就是说C类IP地址由3字节(24位)的网络地址和1字节(8位)的主机地址组成。而C类地址的最高位固定为110(二进制),所以其能表示的地址范围为:11000000 00000000 00000000 00000001 - 11011111 11111111 11111111 11111110,对应的点分十进制即:192.0.0.1-223.255.255.254,子网掩码为255.255.255.0,每个网络支持的最大主机数为256-2(除去私有地址192.168.0.0到192.168.255.255)=254台。
有了IP地址,再回到寻址的问题。IP地址是和子网相关的,对于通一个子网上的设备,其IP地址前缀都是一样的(网络地址),路由器能直接通过地址前缀定位到子网,而不用像使用MAC地址那样无助。由于IP地址必须得等到设备(网卡)接入一个子网之后才能进行分配,在设备还没有IP地址的时候还是需要使用MAC地址来区分设备。一个设备的IP地址是可以变更的,当IP地址变了之后,还怎么唯一确定一个设备呢?所以IP地址切合的是层次结构,不能唯一标识一个设备。一个形象的比喻就是,MAC地址就像自己的ID号,能唯一标识自己,而IP地址就像一个邮编,方便别人找到自己的所在地,两者缺一不可。
4.2 IPV6
由于IPv4协议的地址为32位,所以它可以提供2^32,也就是大约40亿个地址,如果地球人每人一个IP地址的话,IPv4地址已经远远不够,更何况人均持有的入网设备可能要远多于一个,所以IPV4地址迟早会耗尽。IPV6就是在IPV4的基础上做了加长改进,IPV6地址为128位,解决了IPV4地址耗尽的问题。但是由于老的路由器只支持IPV4的IP包,但是无法理解IPV6格式的IP包,所以IPV4到IPV6的迁移需要伴随着路由设备的更新,而且IPV4网络早已广泛使用,所以IPV4到IPV6的迁移是一个较为漫长的过程。
4.3 IP包与接力
数据链路层以帧为单位传输,而在网络层,无论是UDP还是TCP,都是用IP数据包传递信息。IP数据包分为头部和数据,头部是为了能够实现IP协议而附加的信息,数据部分则是真正要传输的数据。
IP包的传输要通过路由器的接力,每个主机和路由中都存在一个路由表,可以根据路由表找到IP数据包传送需要走的路线。就像坐大巴,我们从A城市出发前往D城市,那么可能需要在A城市购票前往B城市,在B城市购票前往C城市,然后再从C城市到达D城市。这个就是路由的过程,只是由于网络被设计为分层的结构,以此基础进行路由效率较高。
路由表包含地址、网关、子网掩码和网卡等等信息,表里描述的是一种规则:如果目的地址符合a规则,那么路由器将IP包发送到a规则规定的中间路由器,该中间路由器收到数据后,会继续根据目的地址和本机路由表重复上述路由规则。如果根据规则,IP包能够从本机网卡发送出去,那么就不用继续路由,直接由本机网卡发送,这个时候IP包已经到目标局域网了。需要注意的是,一个路由器可以拥有多个网卡,也就是可以同时接入多个局域网。就这样,数据从主机出发,根据路由表不断接力,最终达到目标地址所在局域网,然后再由数据链路层根据帧中的MAC地址将数据发送给指定主机。
4.4 ARP协议(Address Resolution Protocol)
IP包正常接力的前提是,对于一个局域网内,每一台主机和路由器都能知道局域网内主机的IP地址和其MAC地址的对应关系,每一台主机或路由中都有一个ARP Cache用以存储局域网内主机IP地址和MAC地址的对应关系,有了这个对应关系,就能通过一个IP地址获取对应的MAC地址。而这个关系通过ARP协议传播到局域网的每个主机和路由:发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
笼统的说,IP地址处于网络层,MAC地址处于数据链路层,相互没有直接关联,通过以太网发送IP数据包时,需要先封装IP地址(网络层),再封装MAC地址(数据链路层)。但由于发送时只知道目标IP地址,不知道其MAC地址,又不能跨网络层和数据链路层,所以需要使用ARP协议。使用ARP协议,可根据网络层IP数据包包头中的IP地址信息解析出目标硬件地址(MAC地址)信息,以保证通信的顺利进行。ARP包需要包裹在一个帧中,它处于数据链路层和网络层之间。IPV6中使用的是NDP协议(Neighbor Discovery Protocol),工作在网络层。
4.4.1 ARP欺骗与防治
ARP协议是建立在网络中各个主机互相信任的基础上的,局域网络上的主机可以自主发送ARP应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机ARP缓存。由此攻击者就可以向某一主机发送伪ARP应答报文,使发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个ARP欺骗。不过ARP欺骗也可以当做正当用途,比如将未登录用户的请求强制转向登录界面。
ARP欺骗防治手段
1. ARP静态配置:由于需要静态配置每一台计算机的ARP表,所以不适用于大型网络。
2. DHCP Snooping:启 DHCP Snooping 功能后,网络中的客户端只有从管理员指定的DHCP服务器获取IP地址,必须将交换机上的端口设置为信任(Trust)和非信任(Untrust)状态,交换机只转发信任端口的 DHCP OFFER/ACK/NAK报文,丢弃非信任端口的 DHCP OFFER/ACK/NAK 报文,从而达到阻断非法DHCP服务器的目的。
4.5 RIP协议(Routing Information Protocol)
IP包正常接力的另一个前提是每个主机和路由器上都有正确且合理的路由表。这个路由表描述了网络的拓扑结构,如果你了解自己的网络连接,可以手写自己主机的路由表,但是一个路由器可能有多个出口,路由表可能会很长,并且周围连接的其他路由器可能会随时发生变动(比如新增路由器或者路由器坏掉),我们就需要路由表能及时将转向导向其他的路由出口,所以需要一种能自动探测网络生成路由表的协议。
RIP协议就是这样一种协议,它是一种动态路由选择协议,通过距离来决定路由表。RIP协议基于距离矢量算法(DistanceVectorAlgorithms),使用“跳数”(即metric)来衡量到达目标地址的路由距离。这种协议的路由器只关心自己周围的世界,只与自己相邻的路由器交换信息,范围限制在15跳(15度)之内,再远它就不关心了。路由器向周围的路由器和主机广播自己前往各个IP的距离,收到RIP数据包的路由器和主机根据RIP包和自己到发送RIP包的主机的距离,算出自己前往各个IP的距离(比如我收到A路由器到IP1的距离为3,而我到A路由器的距离为1,那么我经过A路由到IP1的距离就为3+1=4)。如果计算出来的新距离优于路由表缓存,那么更新路由表,否则保持不变,就这样在各个点不断重复RIP广播/计算距离/更新路由表的过程,最终所有的主机和路由器都能生成最合理的路径。
由于RIP的跳数标准(超过15跳认为不可达),所以RIP更多应用于互联网的一部分。这样一个互联网的部分往往属于同一个ISP或者有同一个管理机构,所以叫做自治系统(AS,autonomous system)。自治系统内部的主机和路由根据通向外部的边界路由器来和其它的自治系统通信。各个边界路由器之间通过BGP(Border Gateway Protocol,边界网关协议)来生成自己前往其它自治系统的路由表,而自治系统内部则参照边界路由器,使用RIP来决定路由表。BGP的基本工作过程与RIP类似,但在考虑距离的同时,也权衡比如政策、连接性能等其他因素,再决定路由表。
4.6 IP协议
IP协议认为自己所处的环境是不可靠的,比如路由器坏掉、电缆断裂等,所以IP数据包在传输过程中如果出现错误,那么IP数据包会直接被丢弃,没有重试之类的补救措施,IP协议保持较为简单的处理流程,更加复杂的数据可靠性控制较由高层协议处理。
前面提到的IP接力是根据路由表抉择路径的,但是在往同一个目的地发送连续的IP数据包的过程中,路由表可能会更新,比如出现了一条新的捷径,那么后发送的IP数据包由于走了新的捷径,就可能比之前发送的IP包先到达目的地,这样就可能导致IP包到达的顺序和发送的顺序不一致。即使IPv6中的Flow Label可以建议路由器将一些IP包保持一样的接力路径,但这只是“建议”,路由器可能会忽略该建议。
4.7 ICMP协议(Internet Control Message Protocol)
ICMP协议处于网络层和传输层之间,用于在IP主机、路由器之间传递控制消息。它基于IP协议,一个ICMP包封装在IP数据包中。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。ICMP协议传输的信息可以分为两类:
一类是错误信息:上面提到的IP协议本身不会保证IP数据包的可靠性,如果IP数据包丢失,那么IP协议不会做什么补救措施,所以上游发送IP数据包的主机或路由器不知道下游数据异常,会继续发送数据包,最终导致数据包丢失。而通过ICMP包,下游的路由器和主机可以将错误信息上报给上游,从而让上游路由器和主机能够做些补救措施,但是ICMP只负责上报信息,后续的处理它并不负责。
一类是咨询类信息:比如某台设备询问路径上的每个路由器都是谁,然后各个路由器同样用ICMP包回答。
有了ICMP协议,人们可以更加方便的对IP协议出现的数据问题进行排查和错误纠正,ping和traceroute这类网络诊断工具就是基于ICMP协议。但是也有骇客利用伪造的IP包引发大量的ICMP错误消息恢复,并将这些 ICMP包导向受害主机,从而形成DOS攻击。
五、传输层
有了上面物理层、数据链路层和网络层协议,两个以太网中的计算机已经可以实现通信了,但是一个计算机中有许多的进程,每个进程都可能有通信的需求。对于每一个进程,我们需要保证数据包准确的送到该进程之中。参照网络层扩展数据链路层的背景,我们也只能在内容数据上添加更加详细的地址:端口。传输层协议(比如TCP、UDP)使用端口号来识别进程,为应用进程提供端到端的通信服务。网络层只是根据IP地址将源结点发出的数据包传送到目的结点,而传输层则负责将数据可靠地传送到相应的端口。
5.1 UDP协议(User Datagram Protocol)
UDP协议的传输和IP协议类似,也是不可靠的,可以将UDP协议看作IP协议暴露在传输层的一个接口,其他没有什么大的区别。之所以设计UDP协议的一个重要原因是,IP协议没有端口的概念,它只是负责IP到IP的传输,但是不同计算机进程之间的通信要依赖端口,也就是传输层协议做的事,UDP协议是一个传输层协议,实现了端口,从而让数据包可以在IP协议的基础上进一步发送到某一个端口。特别是对于不要求可靠性的传输。
5.2 TCP协议(Transmission Control Protocol)
TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。流的特点是顺序,TCP协议是基于IP协议的,所以数据最终还是以IP数据包为单位传输。如果需要传输的数据很长,那么不能将整个数据放到一个IP数据包中,所以TCP协议封装到IP数据包的不是整个数据,而是TCP协议规定的分段(segment)或者叫做片段。分段结构类似于IP数据包,包含头部和数据部分,其中头部包含该片段的序号,依赖该序号,接收方就能做到按照流的顺序接收数据。比如已经接收到了分段1、分段2、分段3,那么接收方就开始期待片段4。如果接收到不符合顺序的数据包(比如分段8),则接收方的TCP模块可以拒绝接收,以达到按顺序接收的目的。一个分段在网络中有最大存活时间,称之为MSL(Maximum Segment Lifetime)。
5.2.1 可靠性保障-ACK和重复发送
由于片段在传输过程中可能会丢失,所以接收主机收到的数据可能是残缺不堪的。TCP的做法是在每收到一个正确的、符合次序的片段之后,就向发送方发送一个特殊的TCP片段作为ACK回执,告知发送方已经接收到该消息。如果一个片段序号为M,那么对应的ACK为M+1,也就是接收方期待接收的下一个片段的序号。如果发送方在一定时间等待之后,还是没有收到ACK回复,那么它就认为之前发送的片段发生了异常。发送方会重复发送那个出现异常的片段,等待ACK回复,如果还是没有收到,那么再重复发送原片段... 直到收到该片段对应的ACK回复。
5.2.2 滑窗管理
按照上面ACK和重复发送的逻辑:发送->等待ACK->发送->等待ACK.......。在等待ACK的时间,网络都处于闲置状态,最好能利用好这个时间。为了解决这个问题,发送方和接收方各有一个滑窗,当片段位于滑窗中时,表示TCP正在处理该片段。滑窗中可以有多个片段,也就是可以同时处理多个片段,滑窗越大,越大的滑窗同时处理的片段数目越多。TCP协议也有实时调整滑窗大小的算法,以提高效率。
我们假设一个可以容纳三个片段的滑窗,片段从左向右排列。对于发送方来说,滑窗的左侧为已发送并收到ACK的片段序列,滑窗右侧是尚未发送的片段序列。滑窗中的片段(比如片段5,6,7)被发送出去,并等待相应的ACK。如果收到片段5的ACK,滑窗将向右移动。这样新的片段从右侧进入滑窗内,被发送出去,并进入等待状态。在接收到片段5的ACK之前,滑窗不会移动,即使已经收到了片段6和7的ACK。这样,就保证了滑窗左侧的序列是已经发送的、接收到ACK的、符合顺序的片段序列。
对于接收方来说,滑窗的左侧是已经正确收到并且回复过ACK的片段(比如片段1,2,3,4),滑窗中是期望接收的片段(比如片段5, 6, 7)。同样,如果片段6,7先到达,那么滑窗不会移动。如果片段5先到达,那么滑窗会向右移动,以等待接收新的片段,如果出现滑窗之外的片段,比如片段9,那么滑窗将拒绝接收。
对于ACK,如果每个TCP分段都回复一个ACK,那么整个网络流量无疑就翻倍了。事实上,可以将ACK和其他数据片段一起发送,并且不用对每个TCP分段都发送ACK,而是通过一个ACK来通知多个分段接收成功,也就是ACK合并。接收方在接收到片段,并应该回复ACK的时候,会故意延迟一些时间,如果在延迟的时间里有后续的片段到达,就可以利用累计ACK来一起回复。比如,滑窗还没接收到片段7时,已经接收到片段8,9。当滑窗最终接收到片段7时,滑窗送出一个回复号为10的ACK回复。发送方收到该回复后会了解到片段10之前的片段已经被成功接收。这个过程就不用发送片段7,8所需的两个ACK。
通过调整滑窗大小,可以方便的控制TCP流量。TCP头部中有部分window size区域,通过这个区域,接收方将window大小通知给发送方,从而指导发送方修改窗口大小,发送方在收到通知后,会调整自己滑窗的大小,如果发送窗口变小,数据发送速率就会降低。
如果接收方不能处理消息,可以通知发送方,指导其将窗口大小变更为0(零窗口),让其停止发送。当接收方经过一段时间的处理,能继续处理消息时,可以以ACK的方式通知发送方,让发送方调整其窗口大小,恢复发送。但是ACK可能会丢失,如果ACK丢失,那么TCP传输就陷入了死锁状态(发送方一直处于零窗口)。为了防止死锁的出现,发送方会在零窗口后,向接收方发送1byte的TCP分段,并等待包含窗口大小的ACK回复,以此当做探测的手段。如果探测结果显示窗口依然为0,发送方会等待更长的时间,然后再次进行窗口探测,直到TCP传输恢复。同时,接收方宣告的窗口必须达到一定的尺寸,否则等待,这是为了防止窗口太小而导致TCP通信分段中包含的数据很小,浪费流量(主要是TCP分段头部),除非需要最小化延迟的TCP应用(比如命令行互动)。
5.2.3 三次握手
它使用三次握手建立全双工连接,流程如下:
-
客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
-
服务器端收到SYN报文,回应一个SYN (SEQ=y)+ ACK(ACK=x+1)报文,进入SYN_RECV状态。
-
客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established(连接已建立)状态。(图片来自网络)
5.2.4 四次挥手
TCP使用四次挥手终止连接。由于TCP连接属于全双工,在一次连接中双方都可以发送数据,所以两端都需要单独进行关闭。客户端主动断开连接的流程如下:
- 一个TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。(主动关闭)
- 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。(服务端执行被动关闭)
- 服务器关闭客户端的连接,发送一个FIN给客户端。
- 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。(图片来自于网络)
TCP连接断开的原则是当一方完成它的数据发送任务后发送一个FIN来终止这个方向的连接,首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。收到一个 FIN只意味着这一方向上没有数据流动,但是一个TCP连接在收到一个FIN后仍能发送数据(另一端)。这主要发生在第二和第三阶段之间:客户端(主动方)到服务器(被动方)的连接断开,但是服务器到客户端的连接还未断开。此时服务端可以继续向客户端发送数据,但是客户端不能向服务器发送数据。
第四步客户端发送的ACK可能会丢失,导致服务器无法收到,服务器如果没有收到ACK,将会不断重复发送FIN片段,直到收到客户端发送的ACK。所以客户端不能立即关闭,客户端会在ACK发出之后进入到一个TIME_WAIT状态,客户端会设置一个计时器,等待2MSL。如果在该时间内再次收到FIN,那么客户端会重发ACK并再次等待2MSL。MSL在前面做过介绍,代表TCP分段的最大存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL的等待时间,客户端都没有再次收到FIN,那么客户端就推断ACK已经被成功接收,则结束TCP连接。
注:以上的描述都是客户端作为断开连接的主动方,事实上服务器也可以作为关闭的主动方
5.2.5 堵塞控制
随着网络设备接入越来越多,网络开始变的繁忙,网络中出现了大量的堵塞。类似于上下班的堵车,IP数据包在网络中经过一个个路由的接力,如果一个路由器过度繁忙,会丢弃一些数据包。UDP协议还好,不用保证数据的可靠性,但是TCP协议需要保证数据的可靠传输。如果包含TCP片段的IP数据包丢失时,TCP协议会重复发送该片段,于是网络中产生了更多的数据包,原本繁忙的状况得到加剧,构成恶性循环,这种情况被称作堵塞崩溃。为了解决这一问题,TCP协议加入了堵塞控制。
TCP协议会探测网络状况,如果网络发生了拥堵,那么会控制自己发送片段的速率,以缓解网络状况。至于探测的方法主要有ACK超时和重复ACK,一旦发送方认为TCP片段丢失,则认为网络中出现堵塞。
5.3 TCP协议和UDP协议
UDP协议的产生要晚于TCP协议。早期的网络开发者开发出IP协议和TCP协议分别位于网络层和传输层,所有的通信都要先经过TCP封装,再经过IP封装(应用层->TCP->IP)。开发者将TCP/IP视为相互合作的套装。但很快网络开发者发现,IP协议的功能和TCP协议的功能是相互独立的。对于一些简单的通信,我们并不需要可靠的传输,也就不需要TCP协议复杂的建立连接和断开连接的方式(特别是在早期网络环境中,如果过多的建立TCP连接,会造成很大的网络负担)。UDP协议随之被开发出来,作为IP协议在传输层的"傀儡"。这样,网络通信可以通过应用层->UDP->IP的封装方式,绕过TCP协议。由于UDP协议本身异常简单,实际上只为IP传输起到了桥梁的作用,而UDP协议也可以相对快速地处理这些简单的通信。
六、应用层
就像现实生活中,不同国家的人可能使用不同的语言,要与一个国家的人交流,需要用他使用的语言,不然就会存在沟通问题。对应到应用程序,一个计算机中不同的进程所做的事可能不一样,而他们所能理解的数据规则也可能不一样,除了让进程能够准确接收数据包外(传输层保证),还需要保证它能够正确理解数据包。应用层协议就是做这样一件事:进一步规范数据包,以达到我们的目的。
6.1 DNS协议
域名是IP地址的代号,通常由字符构成,比如blog.csdn.net,这要比101.200.35.175这种IP格式更加容易记忆。域名解析系统(DNS)就负责将域名翻译为IP地址,域名和IP地址的对应关系存储在DNS服务器,这些服务器是指在网络中进行域名解析的一些服务器(计算机),它们也有自己的IP地址,使用DNS协议进行通信。DNS协议基于UDP协议,属于应用层协议。
DNS服务器构成一个分级的树状体系。上图中(网图),每个节点为一个DNS服务器,每个节点都有自己的IP地址。树的顶端为用户电脑出口处的DNS服务器,树的末端是真正的域名/IP对应关系记录。一次DNS查询就是从树的顶端节点出发,最终找到相应末端记录的过程。在Linux下,可以使用cat /etc/resolv.conf,在Windows下,可以使用ipcofig /all,来
查询出口DNS服务器。
中间节点根据域名的构成,将DNS查询引导向下一级的服务器。比如说一个域名cs.berkeley.edu,DNS解析会将域名分割为cs, berkeley, edu,然后按照相反的顺序查询(edu, berkeley, cs)。出口DNS首先根据edu,将查询指向下一层的edu节点。然后edu节点根据berkeley,将查询指向下一层的berkeley节点,这台berkeley服务器上存储有cs.berkeley.edu的IP地址。
并不是每次域名解析都要完整的经历解析过程,本机DNS Resolver通常都有DNS缓存,在进行DNS查询之前,计算机会先查询缓存。
6.1.1 反向DNS
上面的DNS查询均为正向DNS查询:已经知道域名,想要查询对应IP。而反向DNS(reverse DNS)是已经知道IP的前提下,想要查询域名。
6.2 HTTP协议
即超文本传输协议,是一个简单的请求(request)-响应(response)协议,它通常运行在TCP协议之上,属于应用层协议。它指定了客户端可能发送给服务器什么样的消息,以及得到什么样的响应。
HTTP协议规定了请求和响应的格式,请求包含请求行、请求头、空行和请求体,响应包含状态行、响应头、空行和响应体。
6.2.1 请求行、请求头和请求体
请求行:
只有一行,包含三部分信息,分别是请求的方法(比如POST、GET等),请求的资源路径和HTTP协议的版本。比如 GET /shakespeare/v2/notes/636c1ee16eba/book HTTP/1.1。
HTTP/1.1协议定义的8中请求方法,但是并不是所有的服务器都必须支持所有的请求方法,比如APACHE作为一个网页服务器,支持GET、POST等方法,但是不必支持CONNECT等方法:
-
GET:主要用于从服务器获取资源,也可以用于传输不重要的数据,通过改写URL的方式实现:URL?param={param}&...
-
POST:主要用于向服务器提交数据,数据位于http请求的主体,比如提交表单。
-
HEAD:类似于GET,不过返回的响应中没有数据,响应头中包含的元信息应该和一个GET请求的响应消息相同,常用来测试超链接的有效性、可用性和是否被串改等。
-
DELETE:请求服务器删除Request-URL所标识的资源。
-
CONNECT:HTTP/1.1协议预留的方法,能够将连接改为管道方式的代理服务器。通常用于代理服务器,以代理服务器为跳板代替用户发起请求,然后将数据原模原样的返回。
-
OPTIONS:类似于HEAD方法,这个方法会请求服务器返回该资源所支持的所有HTTP请求方法,该方法会用*来代替资源名称,向服务器发送OPTIONS请求,可以测试服务器功能是否正常。
-
TRACE:请求服务器回显其收到的请求信息,该方法主要用于HTTP请求的测试或诊断。
-
PUT:从语义上来说,PUT方法向指定资源位置(URI)上传其最新内容,如果已经存在则完全覆盖,否则新建。PUT和POST的主要区别可以从幂等性切入,由于PUT是上传最新的内容,服务器原有资源会被完全代替,所以是幂等的。如果只提交部分内容,又需要幂等,那么不要使用PUT(因为会完全覆盖)。而POST在服务端的实现是不可预知的,如果每次更新部分内容,那么不能保证幂等性。
请求头:头信息可以有多行,每一行都是一个键值对,关键字和值用英文冒号“:”分隔。请求头通知服务器有关于客户端请求的信息比如 Content-type: text/plain。头信息是对请求行的补充。
请求体:主体部分包含了具体的资源
6.2.2 状态行、响应头和响应体
状态行:
类似于请求行,响应行也包含三部分信息,分别是协议版本、状态码和状态描述。比如 HTTP/1.1 200 OK,其中OK是对状态码200的描述,只是为了方便人类阅读,计算机只关心状态码,即这里的200,表示一切OK,资源正常返回。状态码有很多,比如302:重定向,404:找不到资源,403:权限不足等等
响应头:类似请求头,Content-type说明了主体所包含的资源的类型。根据类型的不同,客户端可以启动不同的处理程序,比如:
- text/plain:普通文本
- text/html:HTML文本
- application/json; charset=utf-8:json数据,编码为utf-8
响应体:返回的资源,类型参照Content-type。
6.2.3 HTTP请求流程
通过浏览器访问一个网页:
1、浏览器向DNS服务器请求解析该 URL 中的域名所对应的 IP 地址
2、解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立 TCP 连接
3、浏览器发起HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器
4、服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器
5、释放 TCP 连接:若connection 模式为close,则服务器主动关闭TCP 连接,客户端被动关闭连接,释放TCP 连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求
6、浏览器将该 html 文本并显示内容
6.2.4 HTTP/2改进
多路复用(Multiplexing)
在 HTTP/1.1 协议中 ,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制,超过限制数目的请求会被阻塞。所以一些站点会有多个CDN域名,目的就是为了变相解决对同一域名的请求限制问题。多路复用则允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。所以HTTP/2可以不依赖建立多个TCP连接实现多流并行处理。HTTP/2 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息,并行的在同一个TCP连接上流转。
二进制分帧
在HTTP/2(应用层)和传输层之间新加入了一个二进制分帧层。在二进制分帧层中,HTTP/2 把传输的消息分割为更小的消息和帧,并且采用二进制的格式和编码,而非HTTP/1.0的文本格式,效率更高。其中 HTTP1.x 的头部信息会被封装到 HEADER frame,而相应的消息体则封装到 DATA frame 里面。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。
服务器推送
服务端可以在发送HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求。服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。
头部压缩
HTTP/2对消息头采用HPACK(专为HTTP/2头部设计的压缩格式)进行压缩传输,能够节省消息头占用的网络流量。而HTTP/1.x每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。
6.3 DHCP协议(Dynamic Host Configuration Protocol,动态主机配置协议)
DHCP协议基于UDP协议,常被应用在大型的局域网络环境中,主要作用是集中的管理、分配IP地址,使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率。网络上的点对点沟通需要有IP地址,但是新接入网络中的主机需要通过DHCP获取IP地址,所以DHCP需要依赖UDP协议的广播通信,把UDP数据包发送到网络的广播地址上,网络上的每个设备都能收到。
DHCP通信分为四步:
- Discovery:客户机发广播,搜寻DHCP服务器
- Offer:DHCP服务器发出邀请,提供一个可用的IP地址
- Request:客户机正式请求使用该IP地址
- Acknowledge:DHCP服务器确认,并提供其他配置参数
6.3.1 DHCP攻击
针对DHCP的一种攻击办法是从服务器那里骗IP地址。攻击者的电脑可以不断发出DHCP请求,冒充成新入网的客户机。于是DHCP服务器的地址池被耗干,无法分配地址给后来的用户。后来的用户再也没法使用网络服务。攻击者很可能会继续下套,攻击者占有了大量IP地址,可以装扮成新的DHCP服务器,把自己骗来的IP地址分配给网络上的新用户。攻击者伪装DHCP服务器之后,可以让自己成为DNS服务器或者网络的出口。于是客户机的域名解析和外网通信,必须经过攻击者的电脑。这个时候,攻击者可以偷听通信、伪装成客户机、假扮成某个域名的网站。
参考:
百度百科
维基百科