1.2 网络协议
如同人与人之间相互交流是需要遵循一定的规则(如语言)一样,每一层都是为了完成某一种功能。为了实现这些功能,需要遵守一些共同的规则,即网络协议。
OSI参考模型和TCP/IP模型在不同的层次中有许多不同的网络协议,如图所示:
数据链路层
以太网协议
早期的时候,每家公司都有自己的电信号分组方式。逐渐地,一种叫做以太网(Ethernet)
的协议,占据了主导地位。
以太网规定,一组电信号构成一个数据包,叫做帧(frame)
,每一帧分为两个部分:标头(Head)
和数据(Data)
。
MTU(最大传输单元协议)
MTU是链路层对物理层的限制。
- 以太网帧数据段长度规定为46-1500字节,这个最大值1500字节称为以太网的最大传输单元(MTU),不同的网络类型有不同的MTU。
- 如果一个数据包从以太网路由到拨号链路上,数据包长度大于拨号链路的MTU,则需要对数据包进行分片。
MTU对IP协议的影响:
由于链路层存在MTU的限制,导致网络层的报文如果超过1500字节,就必要要对其进行分片发送。
- 将较大的IP包分成多个小包,并给每个小包打上标签,每个小包IP协议头的16位标识(id)都是相同的,这样在重组的时候就知道这个小包来自于哪个报文。
- 每个小包的IP协议头的3位标志字段中, 第2位MF置为0, 表示允许分片, 第3位DF来表示结束标记(当前是否是后一个小包, 是的话置为1, 否则置为0)。
- 到达对端时再将这些小包按顺序重组, 拼装到一起返回给传输层。一旦这些小包中任意一个小包丢失,接收端的重组就会失败,但是IP层不会负责重新传输数据。
MTU对UDP协议的影响:
- 只要UDP报文中携带的数据超过过1472(1500 - 20(IP首部) - 8(UDP首部)),那么就会在网络层分成多个IP数据报。
- 这些IP数据报有任意一个丢失,都会引起接收端网络层重组失败。那么这就意味着,如果UDP数据报在网络层被分片,整个数据被丢失的概率就大大增加。
- 在局域网环境下,建议UDP数据控制在1472字节以下;在Internet环境下,建议将UDP数据控制在548字节以下。
MTU对TCP协议的影响:
- TCP报文的长度不能无限大,依然要受制于MTU, TCP的单个数据报的最大消息长度称为MSS(Max Segment Size)。
- TCP在建立连接时,首先会和对方协商MSS的大小(也只能在三次握手时协商,否则就是默认值536字节)。理想的情况下,MSS的值正好是在IP不会被分片处理的大长度(这个长度仍然是受制于数据链路层的MTU)
- 双方在发送SYN的时候会在TCP头部写入自己能支持的MSS值。然后双方得知对方的MSS值之后选择较小的作为最终的MSS。MSS的值就是在TCP首部的40字节变长选项中(kind=2)。
- MSS = MTU - TCP首部 - IP首部,既TCP报文的数据长度。
MAC地址
以太网数据包的标头,包含了发送者和接受者的信息。那么,发送者和接受者是如何标识呢?
以太网规定,连入网络的所有设备,都必须具有网卡接口。数据包必须是从一块网卡,传送到另一块网卡。网卡的地址,就是数据包的发送地址和接收地址,这叫做MAC地址。
每块网卡出厂的时候,都有一个全世界独一无二的MAC地址,长度是48个二进制位,通常用12个十六进制数表示。
前6个十六进制数是厂商编号,后6个十六进制数是该厂商的网卡流水号。有了MAC地址,就可以定位网卡和数据包的路径了。
广播
定义地址只是第一步,后面还有更多的步骤:
-
1)首先:一块网卡怎么会知道另一块网卡的MAC地址?
有一种ARP协议,可以解决这个问题。以太网数据包必须知道接收方的MAC地址,然后才能发送。
-
2)其次:就算有了MAC地址,系统怎样才能把数据包准确送到接收方?
以太网采用了一种很原始的方式,它不是把数据包准确送到接收方,而是向本网络内所有计算机发送,让每台计算机自己判断,是否为接收方。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m2z9qalt-1606711101959)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201115222312282.png)]
上图中,5号计算机向3号计算机发送一个数据包,同一个子网络的1号、2号、3号、4号、6号计算机都会收到这个包。它们读取这个包的标头,找到接收方的MAC地址,然后与自身的MAC地址相比较,如果两者相同,就接收这个包,做进一步处理,否则就丢弃这个包。这种发送方式就叫做广播(broadcasting)。
有了数据包的定义、网卡的MAC地址、广播的发送方式,"链接层"就可以在多台计算机之间传送数据了。
网络层
以太网协议,依靠MAC地址发送数据。理论上,单单依靠MAC地址,成都的网卡就可以找到休斯顿的网卡了,技术上是可以实现的。
但是,这样做有一个重大的缺点。以太网采用广播方式发送数据包,所有成员人手一包,不仅效率低,而且局限在发送者所在的子网络。也就是说,如果两台计算机不在同一个子网络,广播是传不过去的。这种设计是合理的,否则互联网上每一台计算机都会收到所有包,那会引起灾难。
互联网是无数子网络共同组成的一个巨型网络,很像想象成都和休斯顿的电脑会在同一个子网络,这几乎是不可能的。
因此,必须找到一种方法,能够区分哪些MAC地址属于同一个子网络,哪些不是。如果是同一个子网络,就采用广播方式发送,否则就采用路由方式发送。(路由的意思,就是指如何向不同的子网络分发数据包,这是一个很大的主题,本文不涉及。)遗憾的是,MAC地址本身无法做到这一点。它只与厂商有关,与所处网络无关。
这就导致了网络层的诞生。它的作用是引进一套新的地址,使得我们能够区分不同的计算机是否属于同一个子网络。这套地址就叫做网络地址,简称网址。
于是,网络层出现以后,每台计算机有了两种地址,一种是MAC地址,另一种是网络地址。两种地址之间没有任何联系,MAC地址是绑定在网卡上的,网络地址则是管理员分配的,它们只是随机组合在一起。
网络地址帮助我们确定计算机所在的子网络,MAC地址则将数据包送到该子网络中的目标网卡。因此,从逻辑上可以推断,必定是先处理网络地址,然后再处理MAC地址。
IP协议
规定网络地址的协议,叫做IP协议。它所定义的地址,就被称为IP地址。目前,广泛采用的是IP协议的第四版和第六版,分别称为IPv4和IPv6。
互联网上的每一台计算机,都会分配到一个IP地址。
这个地址分成两个部分,前一部分代表网络,后一部分代表主机。
比如,IPV4地址14.215.177.39,这是一个32位的地址,假定它的网络部分是前24位(14.215.177),那么主机部分就是后8位(最后的那个1)。处于同一个子网络的电脑,它们IP地址的网络部分必定是相同的,也就是说14.215.177.2应该与14.215.177.1处在同一个子网络。
但是,问题在于单单从IP地址,我们无法判断网络部分。还是以14.215.177.39为例,它的网络部分,到底是前24位,还是前16位,甚至前28位,从IP地址上是看不出来的。那么,怎样才能从IP地址,判断两台计算机是否属于同一个子网络呢?这就要用到另一个参数子网掩码
(subnet mask)。
子网掩码:
- 所谓子网掩码,就是表示子网络特征的一个参数。它在形式上等同于IP地址,也是一个32位二进制数字,它的网络部分全部为1,主机部分全部为0。比如,IP地址172.16.254.1,如果已知网络部分是前24位,主机部分是后8位,那么子网络掩码就是11111111.11111111.11111111.00000000,写成十进制就是255.255.255.0。
- 知道子网掩码,我们就能判断,任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行按位与运算(两个数位都为1,运算结果为1,否则为0),然后比较结果是否相同,如果是的话,就表明它们在同一个子网络中,否则就不是。
NAT:
我们知道,IPv4的地址只有32位,地球上网民数量已经远远超出这个数字,那么,为啥至今还没出现地址枯竭呢?
因为我们还有一些技术,可以变相的缓解地址不足,比如NAT技术。
- 每一个小的局域网,都会使用一个网段的私网地址,在与外界连接时,再变换成公网地址。这样一来,几十个或几百个电脑,都只需要一个公网地址。
- 甚至还可以私网套私网,NAT套NAT,一层一层套。这样一来,大大节约了公网IP地址数量。正因为如此,才让我们“续命”到了今天,不至于无法上网。
- 但是,NAT这种方式也有很多缺点,虽然私网地址访问互联网地址方便,但互联网地址访问私网地址就困难了。很多服务,都会受到限制,你只能通过复杂的设置才能解决,也会影响网络的处理效率。
IPv6:
IPv6是用来解决IPv4地址枯竭问题的,IPv4地址为32位,而IPv6地址为128位 除了地址数量以外,IPv6还有很多优点,例如:
- IPv6使用更小的路由表。使得路由器转发数据包的速度更快;
- IPv6增加了增强的组播支持以及对流的控制,对多媒体应用很有利,对服务质量(QoS)控制也很有利;
- IPv6加入了对自动配置的支持。这是对DHCP协议的改进和扩展,使得网络(尤其是局域网)的管理更加方便和快捷;
- IPv6具有更高的安全性。用户可以对网络层的数据进行加密并对IP报文进行校验,极大地增强了网络的安全性;
- IPv6具有更好的扩容能力。如果新的技术或应用需要时,IPV6允许协议进行扩充;
- IPv6具有更好的头部格式。IPV6使用新的头部格式,就简化和加速了路由选择过程,提高了效率;
总结:
IP协议的作用在于把各种数据包准备无误的传递给对方,其中两个重要的条件是IP地址和MAC地址。由于IP地址是稀有资源,不可能每个人都拥有一个IP地址,所以我们通常的IP地址是路由器给我们生成的IP地址,路由器里面会记录我们的MAC地址。而MAC地址是全球唯一的。举例,IP地址就如同是我们居住小区的地址,而MAC地址就是我们住的那栋楼那个房间那个人。IP地址采用的IPv4格式,目前正在向IPv6过渡。
IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已 经用尽。以点分十进制表示,如192.168.0.1
IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示, 数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c 8ff:fe4d:db39:1984
分类:公网地址(万维网使用)和私有地址(局域网使用)。192.168. 开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机 构内部使用
IP数据包
根据IP协议发送的数据,就叫做IP数据包。我们直接把IP数据包直接放进以太网数据包的"数据"部分,不用修改以太网的规格。这就是互联网分层结构的好处:上层的变动完全不涉及下层的结构。
具体来说,IP数据包也分为标头和数据两个部分:其中,标头范围为20-60字节(IPv6固定为40字节),整个数据包的总长度最大为65535字节。因此,理论上,一个IP数据包的数据部分,最长为65515字节。
如图所示,标头中20字节是固定不变的,它包含了版本、长度、IP地址等信息,另外还有可变部分的标头可选。而数据则是IP数据包的具体内容。
将它放入以太网数据包后,以太网数据包就变成了下面这样:
在以太网协议中,以太网数据包的数据部分,最长只有1500字节。因此,如果IP数据包超过了1500字节,它就需要分割成几个以太网数据包,分开发送了。
ARP协议
关于网络层,还有最后一点需要说明。因为IP数据包是放在以太网数据包里发送的,所以我们必须同时知道两个地址,一个是对方的MAC地址,另一个是对方的IP地址。通常情况下,对方的IP地址是已知的,但是我们不知道它的MAC地址。所以,我们需要一种机制,能够从IP地址得到MAC地址。
这里又可以分成两种情况:
- 第一种情况:如果两台主机不在同一个子网络,那么事实上没有办法得到对方的MAC地址,只能把数据包传送到两个子网络连接处的网关(gateway),让网关去处理;
- 第二种情况:如果两台主机在同一个子网络,那么我们可以用ARP协议,得到对方的MAC地址。ARP协议也是发出一个数据包(包含在以太网数据包中),其中包含它所要查询主机的IP地址,在对方的MAC地址这一栏,填的是FF:FF:FF:FF:FF:FF,表示这是一个广播地址。它所在子网络的每一台主机,都会收到这个数据包,从中取出IP地址,与自身的IP地址进行比较。如果两者相同,都做出回复,向对方报告自己的MAC地址,否则就丢弃这个包。
总之,有了ARP协议之后,我们就可以得到同一个子网络内的主机MAC地址,可以把数据包发送到任意一台主机之上了。
ARP攻击
传输层
有了MAC地址和IP地址,我们已经可以在互联网上任意两台主机上建立通信。
接下来的问题是,同一台主机上有许多程序都需要用到网络,比如,你一边浏览网页,一边与朋友在线聊天。当一个数据包从互联网上发来的时候,你怎么知道,它是表示网页的内容,还是表示在线聊天的内容?
也就是说,我们还需要一个参数,表示这个数据包到底供哪个程序(进程)使用。这个参数就叫做端口(port),它其实是每一个使用网卡的程序的编号。每个数据包都发到主机的特定端口,所以不同的程序就能取到自己所需要的数据。
端口是0到65535之间的一个整数,正好16个二进制位。0到1023的端口被系统占用,用户只能选用大于1023的端口。不管是浏览网页还是在线聊天,应用程序会随机选用一个端口,然后与服务器的相应端口联系。
传输层的功能,就是建立端口到端口的通信。相比之下,网络层的功能是建立主机到主机的通信。只要确定主机和端口,我们就能实现程序之间的交流。因此,Unix系统就把主机+端口,叫做套接字(socket)。有了它,就可以进行网络应用程序开发了。
TCP协议
TCP(传输控制协议)是面向连接的传输层协议。传输层是位于网络层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是网络层不提供这样的流机制,而是提供不可靠的包交换。TCP协议采用字节流传输数据。因此,TCP协议能够确保数据不会遗失。它的缺点是过程复杂、实现困难、消耗较多的资源。
-
TCP的报文格式
TCP报文段包括协议首部和数据两部分,协议首部的固定部分是20个字节,首部的固定部分后面是选项部分。
源端口号以及目的端口号:各占2个字节,端口是传输层和应用层的服务接口,用于寻找发送端和接收端的进程,一般来讲,通过端 口号和IP地址,可以唯一确定一个TCP连接,在网络编程中,通常被称为一个socket接口
序号:Seq序号,占4个字节、32位。用来标识从TCP发送端向TCP接收端发送的数据字节流。发起方发送数据时对此进行标记。
确认序号:Ack序号,占4个字节、32位。包含发送确认的一端所期望收到的下一个序号。只有ACK标记位为1时,确认序号字段才有 效,因此,确认序号应该是上次已经成功收到数据字节序号加1,即Ack=Seq + 1。
数据偏移:占4个字节,用于指出TCP首部长度,若不存在选项,则这个值为20字节,数据偏移的最大值为60字节。
保留字段:占6位,暂时可忽略,值全为0。
标志位:6个
URG(紧急):为1时表明紧急指针字段有效
ACK(确认):为1时表明确认号字段有效
PSH(推送):为1时接收方应尽快将这个报文段交给应用层
RST(复位):为1时表明TCP连接出现故障必须重建连接
SYN(同步):在连接建立时用来同步序号
FIN(终止):为1时表明发送端数据发送完毕要求释放连接
接收窗口:占2个字节,用于流量控制和拥塞控制,表示当前接收缓冲区的大小。在计算机网络中,通常是用接收方的接收能力的大 小来控制发送方的数据发送量。TCP连接的一端根据缓冲区大小确定自己的接收窗口值,告诉对方,使对方可以确定发送数据的字节 数。
校验和:占2个字节,范围包括首部和数据两部分。
-
三次握手
TCP是面向连接的协议,因此每个TCP连接都有3个阶段:连接建立、数据传送和连接释放。连接建立经历三个步骤,通常称为“三次握手”。
1.第一次握手(客户端发送请求)
客户机发送连接请求报文段到服务器,并进入SYN_SENT状态,等待服务器确认。发送连接请求报文段内容:SYN=1,seq=x;SYN=1意思是一个TCP的SYN标志位置为1的包,指明客户端打算连接的服务器的端口;seq=x表示客户端初始序号x,保存在包头的序列号(Sequence Number)字段里。
2. 第二次握手(服务端回传确认)
服务器收到客户端连接请求报文,如果同意建立连接,向客户机发回确认报文段(ACK)应答,并为该TCP连接分配TCP缓存和变量。服务器发回确认报文段内容:SYN=1,ACK=1,seq=y,ack=x+1;SYN标志位和ACK标志位均为1,同时将确认序号(Acknowledgement Number)设置为客户的ISN加1,即x+1;seq=y为服务端初始序号y。
3. 第三次握手(客户端回传确认)
客户机收到服务器的确认报文段后,向服务器给出确认报文段(ACK),并且也要给该连接分配缓存和变量。此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。客户端发回确认报文段内容:ACK=1,seq=x+1,ack=y+1;ACK=1为确认报文段;seq=x+1为客户端序号加1;ack=y+1,为服务器发来的ACK的初始序号字段+1。
注意:握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
-
四次挥手
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
- TCP客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态。发送报文段内容:FIN=1,seq=u;FIN=1表示请求切断连接;seq=u为客户端请求初始序号。
- 服务端收到这个FIN,它发回一个ACK给客户端,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号;服务端进入CLOSE_WAIT状态。发送报文段内容:ACK=1,seq=v,ack=u+1;ACK=1为确认报文;seq=v为服务器确认初始序号;ack=u+1为客户端初始序号加1。
- 服务器关闭客户端的连接后,发送一个FIN给客户端,服务端进入LAST_ACK状态。发送报文段内容:FIN=1,ACK=1,seq=w,ack=u+1;FIN=1为请求切断连接,ACK=1为确认报文,seq=w为服务端请求切断初始序号。
- 客户端收到FIN后,客户端进入TIME_WAIT状态,接着发回一个ACK报文给服务端确认,并将确认序号设置为收到序号加1,服务端进入CLOSED状态,完成四次挥手。发送报文内容:ACK=1,seq=u+1,ack=w+1;ACK=1为确认报文,seq=u+1为客户端初始序号加1,ack=w+1为服务器初始序号加1。
客户端发送FIN后,进入终止等待状态,服务器收到客户端连接释放报文段后,就立即给客户端发送确认,服务器就进入CLOSE_WAIT状态,此时TCP服务器进程就通知高层应用进程,因而从客户端到服务器的连接就释放了。此时是“半关闭状态”,即客户端不可以发送给服务器,服务器可以发送给客户端。
此时,如果服务器没有数据报发送给客户端,其应用程序就通知TCP释放连接,然后发送给客户端连接释放数据报,并等待确认。客户端发送确认后,进入TIME_WAIT状态,但是此时TCP连接还没有释放,然后经过等待计时器设置的2MSL后,才进入到CLOSE状态。为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
-
TCP协议的流量控制
win反映的是窗口的剩余大小,ACK表示目前接收端接收到的数据的序号。发端根据这个序号和收端剩余的大小就可以调整自己下一步发送多少,这就是流量控制的基本思想。
对于发送端的数据缓冲区有这些量:LastByteSent是目前发送的最后1比特的数据编号;LastByteAckd是目前接收到确认的最后1比特的数据编号;Revwin是窗口大小。鉴于每次发送方都是收到ACK之后滑动窗口继续发送,发送到LastByteSent这个位置,LastByteSent-LastByteAckd也就是这次发送数据的多少,那么只要满足:LastByteSent–LastByteAckd<=RcvWin(接收端空闲窗口大小) 就会保证不会溢出了。
那么接收端RcvWin怎么算呢?假设接收端缓冲区大小为RcvBuffer。LastByteRead:上层应用程序接收的最后一个字节序号,LastByteRcvd:接收端从网络接收的最后一个字节序号,那么LastByteRcvd–LastByteRead就是已经接受但是还没有传递给上层的数据。所以空闲区域RcvWin= RcvBuffer-(LastByteRcvd–LastByteRead).
接收端通过计算出空闲区域Recwin,在把这个消息反馈给发送方,发送方借此调整发送速率,进而实现TCP的端端流量控制。
-
TCP协议的拥塞控制
TCP的拥塞控制是通过调节拥塞窗口的大小来进行的,拥塞窗口(CongWin)体现出来了网络的承受能力;网络层已经出现了缓存溢出的情况,不能再继续接收数据包,否则会出现丢包的情况,TCP的拥塞控制就是限制发送和进来的流量大小,与流量控制不同的是,流量控制是告诉发送方我还的接收容器有多大,我能接收多少,而TCP的拥塞控制是,网络层出现了拥塞,已超出负荷,就算你接收方能接收那么多数据,但是我传不过去。发送端的有效窗口必须兼顾网络和接收能力:SendWin = min(接收窗口,拥塞窗口),发送端必须凭借此公式调整发送速率以避免网络拥塞造成的丢包。如下图的示意图,网络中限制传输速率一定是由最小的那一环决定的,而这一环往往取决于内部的拥塞,所以用拥塞窗口来调节发送速率是一个非常好的选择。
那么回到拥塞控制本身。拥塞控制有几个问题需要解决:第一,如何知晓自己的线路发生了拥塞?第二,发生了拥塞,用什么算法进行处理?TCP拥塞控制为这两个问题给出了自己的答案。
第一,怎么判定网络的拥塞?①发送端的计时器超时了。当发生拥塞时,发送端和接收端之间路径上一个或者多个路由器的缓冲区溢出,导致数据报被丢弃。这会导致发送方长时间收不到反馈从而导致超时; ②收到三个重复的ACK(快速重传机制) 简单来说,就是某一个包丢了,但是它之后的包都正常达到,那么接受方发现只有某一个包丢了,就向源端连续发送三个ACK,ACK带有期待的包的序号,发送端收到这三个连续ACK,便不等到段计时器超时,直接发送对应的序号的数据包,这就是快速重传机制。这两个方法,能让发送方掌握网络发生了拥塞,进而采用算法来调整自己的发送速率。
第二,采用什么算法。我们假设接收缓冲区足够大,那么对于 min(接收窗口,拥塞窗口),实际中起到影响作用的只有拥塞窗口CongWin. 设 RTT 为TCP段开始发送到ACK返回的时间,也就是一个数据包发送所需要的时间,那么发送端的发送速率近似为CongWin/RTT bps。 所以TCP发送端通过调整CongWin来限制发送速率。
UDP协议
UDP,用户数据报协议,它是TCP/IP协议簇中无连接的运输层协议。
- UDP是一个非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
- 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务器可同时向多个客户端传输相同的消息。
- UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
- 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
- UDP使用尽量最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表。
- UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部受就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。
- UDP报文格式
UDP协议由两部分组成:首部和数据。其中,首部仅有8个字节,包括源端口和目的端口、长度(UDP用于数据报的长度)、校验和。
- UDP和TCP的区别
- TCP基于连接,UDP是无连接的;
- 对系统资源的要求,TCP较多,UDP较少;
- UDP程序结构较简单;
- TCP是流模式,而UDP是数据报模式;
- TCP保证数据正确性,而UDP可能丢包;TCP保证数据顺序,而UDP不保证;
- 流模式和数据报模式的区别
流模式相当于蓄水池,你发过来的数据,我先存到蓄水池里,我用时就从蓄水池里面取即可;数据报模式是你发几次我就取几次,DP是基于报文的,在接收的时候,每次最多只能读取一个报文,报文和报文是不会合并的,如果缓冲区小于报文长度,则多出的部分会被丢弃。也就说,如果不指定MSG_PEEK标志,每次读取操作将消耗一个报文。UDP是无连接的协议,也就是说,只要知道接收端的IP和端口,且网络是可达的,任何主机都可以向接收端发送数据。这时候,如果一次能读取超过一个报文的数据,则会乱套。比如,主机A向发送了报文P1,主机B发送了报文P2,如果能够读取超过一个报文的数据,那么就会将P1和P2的数据合并在了一起,这样的数据是没有意义的。
UDP中一个包的大小最大能多大:
-
局域网环境下,建议将UDP数据控制在1472字节以下
-
- 以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的,这个1500字节被称为链路层的MTU(最大传输单元)。但这并不是指链路层的长度被限制在1500字节,其实这这个MTU指的是链路层的数据区,并不包括链路层的首部和尾部的18个字节。
- 所以,事实上这个1500字节就是网络层IP数据报的长度限制。因为IP数据报的首部最小为20字节,所以IP数据报的数据区长度最大为1480字节。而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的。
- 又因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节。这个1472字节就是我们可以使用的字节数。
- 当我们发送的UDP数据大于1472的时候会怎样呢?这也就是说IP数据报大于1500字节,大于MTU,这个时候发送方IP层就需要分片(fragmentation)。把数据报分成若干片,使每一片都小于MTU,而接收方IP层则需要进行数据报的重组。这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方无法重组数据报,将导致丢弃整个UDP数据报。
- 因此,在普通的局域网环境下,我建议将UDP的数据控制在1472字节以下为好。
-
Internet编程时,建议将UDP数据控制在548字节以下
-
- 进行Internet编程时则不同,因为Internet上的路由器可能会将MTU设为不同的值。如果我们假定MTU为1500来发送数据,而途经的某个网络的MTU值小于1500字节,那么系统将会使用一系列的机制来调整MTU值,使数据报能够顺利到达目的地,这样就会做许多不必要的操作。
- 鉴于Internet上的标准MTU值为576字节,所以我建议在进行Internet的UDP编程时, 最好将UDP的数据长度控件在548字节(576-8-20)以内。
- ps:这句话貌似有问题,unix网络编程第一卷里说:ipv4协议规定ip层的最小重组缓冲区大小为576!所以,建议udp包不要超过这个大小,而不是因为internet的标准MTU是576!
应用层
应用程序收到传输层的数据,接下来就要进行解读。由于互联网是开放架构,数据来源五花八门,必须事先规定好格式,否则根本无法解读。应用层的作用,就是规定应用程序的数据格式。
因此,现在的以太网的数据包就变成下面这样:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AVtho7Si-1606711101974)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201115224823305.png)]
TCP包括:
- FTP协议
- HTTP协议
- TELNET协议
- SMTP协议
UDP包括:
- DNS协议
- TFTP协议
HTTP协议
HTTP,超文本传输协议,它是互联网上应用最为广泛的一种网络协议。HTTP是一种应用层协议,它是基于TCP协议之上的请求/响应式的协议。HTTP协议是Web浏览器和Web服务器之间通信的标准协议。HTTP指定客户端与服务器如何建立连接、客户端如何从服务器请求数据,服务器如何响应请求,以及最后如何关闭连接。HTTP连接使用TCP/IP来传输数据。
对于从客户端到服务器的每一个请求,都有4个步骤:
- 默认情况下,客户端在端口80打开与服务器的一个TCP连接,URL中还可以指定其他端口。
- 客户端向服务器发送消息,请求指定路径上的资源。这个资源包括一个首部,可选地(取决于请求的性质)还可以有一个空行,后面是这个请求的数据。
- 服务器向客户端发送响应。响应以响应码开头,后面是包含数据的首部、一个空行以及所请求的文档或错误消息。
- 服务器关闭连接。
无连接
现在使用的HTTP协议是HTTP/1.1版本,1997年之前采用的是HTTP1.0版本。HTTP连接在1.0版本中采用非持续连接工作方式,1.1版本采用的长连接工作方式。
是否采用持续连接工作方式,1.0中默认是关闭的,需要在HTTP头加入“Connection:Keep-Alive”,才能启用Keep-Alive。HTTP1.1中默认启用Keep-Alive,如果加入“Connection:close”,才关闭。目前大部分浏览器都是用HTTP1.1协议,也就是说默认都会发起Keep-Alive的连接请求了,所以是否能完成一个完整的Keep-Alive连接就看服务器设置情况。
无状态保存
使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产 生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成 如此简单的。可是,随着Web的不断发展,因无状态而导致业务处理变得棘手 的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的 其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能 够掌握是谁送出的请求,需要保存用户的状态。HTTP/1.1虽然是无状态协议,但为了实现期望的保持状态功能, 于是引入了Cookie技术。有了Cookie再用HTTP协议通信,就可以管理状态了。
HTTP报文
-
HTTP请求报文的格式:
GET /562f25980001b1b106000338.jpg HTTP/1.1 Accept: application/json, text/plain, */* Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cache-Control: no-cache Connection: keep-alive Cookie: _lxsdk_cuid=1753ef94ecac8-0eadcfe7efa321-c781f38-144000-1753ef94ecac8; _lxsdk=1753ef94ecac8-0eadcfe7efa321-c781f38-144000-1753ef94ecac8; uuid=61c107003c5b4b20bfd0.1603079390.1.0.0; mtcdn=K; userTicket=jctwwndApKZkxXsiiTilPZyfhxTqHVWLkXczsEOz; n=zoey%E6%82%A6.; lsu=; _ga=GA1.2.256991000.1603079850; _gid=GA1.2.654682456.1603079850; com.sankuai.meishi.fe.kdb-bsid=wKpZmQZOoSYInLD2lHHG7uvXCVGRdH56VdXNqTdTiGPQWX-BnDRh-vF164-5RkPnFHUNL0VjBNDKX5xsgxwOcQ; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; lt=gHVC1rWeuWYb-XKFLqqrtoe_zLUAAAAAygsAAFUs9jUDqShMkZSqxNYeiaoRmRhcsh5TzINnB2yUa-R_mssUj_TGwlWUuVn2ggHNYw; u=91332875; unc=zoey%E6%82%A6.; firstTime=1603096279866; device_uuid=!3c743f80-c182-4a32-8a2c-ce8793b36f83; acctId=73258913; wmPoiId=9363896; _source=PC; bsid=wKpZmQZOoSYInLD2lHHG7uvXCVGRdH56VdXNqTdTiGPQWX-BnDRh-vF164-5RkPnFHUNL0VjBNDKX5xsgxwOcQ; virtual=0; vacctId=0; acctName=null; token=0FiLouP2WLCVVXcmj7gSPc1WpX9yJ0587sWTIj2e9Xik*; _lxsdk_s=1754384c46b-5b8-4e4-8ad%7C%7C279 DNT: 1 Host: waimaieapp.meituan.com Pragma: no-cache Referer: https://waimaieapp.meituan.com/frontweb/userComment?_source=PC&token=0FiLouP2WLCVVXcmj7gSPc1WpX9yJ0587sWTIj2e9Xik*&acctId=73258913&wmPoiId=9363896®ion_id=1000230100&device_uuid=!6f2761eb-8ced-4f97-9221-bd1a888cf088&bsid=wKpZmQZOoSYInLD2lHHG7uvXCVGRdH56VdXNqTdTiGPQWX-BnDRh-vF164-5RkPnFHUNL0VjBNDKX5xsgxwOcQ&appType=3&fromPoiChange=false Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
-
请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。
-
请求头(首部行)
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔;用来说明服务器要使用的附加信息
-
空行
请求头部后面的空行是必须的,即使第四部分的请求数据为空,也必须有空行。
-
请求体
请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。
-
-
HTTP响应报文格式:
- 状态行、响应行(首部行)、空行、响应体
HTTP请求方法
- 在HTTP1.0中,定义了三种请求方法:
GET
,POST
和HEAD
方法。 - 在HTTP1.1中,新增了五种请求方法:
OPTIONS
,PUT
,DELETE
,TRACE
和CONNECT
方法
但我们常用的一般就是GET和POST请求。
GET和POST请求都有哪些区别呢?
- GET请求在URL中传送的参数是有长度限制的,而POST没有。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。而POST数据不会显示在URL中。是放在Request body中。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET请求参数会被完整保留在浏览器历史记录里;相反,POST请求参数也不会被浏览器保留。
- GET请求只能进行url编码(application/x-www-form-urlencoded),而POST支持多种编码方式。
- GET请求会被浏览器主动缓存,而POST不会,除非手动设置。
- GET在浏览器回退时是无害的,而POST会再次提交请求。
Get请求有Request body么?如果有的话参数可以像Post请求一样放在里面么?
GET和POST在本质上没有区别,都是HTTP协议中的两种发送请求的方法。而HTTP呢,是基于TCP/IP的关于数据如何在万维网中如何通信的协议。
HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。
GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。
URL中传送参数的长度限制在Get和Post中都是怎么样的呢?
果你用GET服务,在request body偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略。
Get方式不同浏览器都有不同的url的长度限制,但是requestBody就不存在了
是不是POST 方法比 GET 方法更安全呢?
有人说POST 比 GET 安全,因为数据在地址栏上不可见。然而,从传输的角度来说,他们都是不安全的,因为 HTTP 在网络上是明文传输的,只要在网络节点上捉包,就能完整地获取数据报文。其实,要想安全传输,就只有加密,也就是 HTTPS。
Get、Post请求发送的数据包有什么不同吗?
- GET:浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
- POST:浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 OK(返回数据)。
- GET与POST都有自己的语义,不能随便混用。
- 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
- 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。我去年用Chrome浏览器测试发现也是只发送一次,所以我认为Get、POST性能差可以人为忽略。
HTTP响应状态码、请求头、响应头
下表是其他状态码,总共5大类,33种。
请求头
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
Content-Type字段:
-
GET 请求
GET 请求不存在请求实体部分,键值对参数放置在 URL 尾部,因此请求头不需要设置 Content-Type 字段
非 ASCII 码会自动进行编码转换,例如发送请求:www.bilibili.com?hehe=你的我的
GET /?hehe=%E4%BD%A0%E7%9A%84%E6%88%91%E7%9A%84 HTTP/1.1
值得一提的是,GET 参数的编码方式是无法人为干涉的,这导致了不同浏览器有不同的编码方式,因此最稳妥的方案是人工预编码,人工解码,从而禁止浏览器编码的干涉
-
POST 请求
-
raw 原始类型,可以上传任意格式的文本,比如 text、json、xml、html;text/plain、application/json、text/html(中文不进行编码)
-
application/x-www-form-urlencoded,会将表单内的数据转换拼接成 key-value
application/x-www-form-urlencoded 对非 ASCII 的编码方式与 GET 请求参数的编码方式和格式都是一样的
POST 请求的编码格式是可以人工干预的:在 form 表单所在的 html 文件里如果有段,那么 post 就会用此处指定的编码方式编码,JSP 也有类似的声明方式;开发人员可以用此来指定 POST 请求的编码格式
-
multipart/form-data,将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件
-
Connection字段:
HTTP也可以建立长连接的,使用Connection:keep-alive
,HTTP 1.1默认进行长连接。
HTTP1.1 和 HTTP1.0 相比较而言,最大的区别就是增加了长连接支持
HTTP和HTTPS的区别
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单来说就是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。它是一个URL scheme(抽象标识符体系),句法类同http:体系,用于安全的HTTP数据传输。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息。HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此HTTP协议不适合传输一些敏感信息,比如信用开号、密码等。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS。为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
HTTPS和HTTP的区别主要为以下四点:
- https协议需要到ca申请证书,一般免费证书很少,需要缴费。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;https协议是有ssl+http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
HTTP和TCP/IP协议的关系
网络中有一段比较容易理解的介绍:
“我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,无法打开对应的资源,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等,也 可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上。”