赞
踩
当一台设备上的不同进程间进行通信,可以通过管道,消息队列,共享内存,信号等方式,而对于不同设备上的进程间通信,就需要网络通信,由于设备种类很多,最后就总结出了一种适用于所有设备的通信网络协议。
一共分为五层,从上至下分别为:应用层,传输层,网络层,数据链路层,物理层。
应用层:帮助用户实现应用功能。
最上面的一层,包括手机软件或者电脑软件,专注于帮助用户实现应用功能,顶层是不需要关心数据是如何传输的,交给底层就好。同时,应用层是工作于操作系统中的用户态的,传输层及以下是工作于内核态的。
传输层:帮助应用层实现通信。
有TCP和UDP两种传输协议。
TCP(Transmission Control Protocol),大部分应用使用的都是TCP协议,比如HTTP应用层协议。TCP比UDP多了很多特性,比如流量控制,超时重传,拥塞控制等。这些都保证了数据包能可靠的传输给对方。
UDP没有TCP可靠,甚至不确定传出去的数据包能不能到对方那里,但往往UDP实时性更好,传输效率高。如果要实现UDP的可靠传输,那就需要在应用层上实现TCP的特性。
应用需要传输的数据往往很大,如果直接传输的话会不太好,因此当传输层的数据包超过了MSS(TCP最大报文段长度),就要将数据分块,这样即使中途有一个分块丢失或损坏了,也只需要重新这一个分块,而不用重新发送整个数据包。每个分块称为TCP段(TCP Segment)。
传输层的报文中携带端口号,接收方可以识别出报文是发送给哪个应用的。
网络层:实际的传输功能,负责将数据从一个设备传输到另一个设备。
最常使用的是IP协议,IP协议会将传输层的报文作为数据部分,加上IP包头组装成IP报文,如果超过MTU(1500)就会再次分片,得到一个即将发送到网络的IP报文。
网络层中有区分设备的编号——IP地址(传输层中的报文有端口号,识别的是具体是哪个应用,网络层中识别的是哪个设备)。
IP地址的两种意义:
一个是网络号,负责标识该IP地址是属于哪个子网的。
一个是主机号,负责标识同一子网下的不同主机。
(需要子网掩码才能算出IP地址的网络号和主机号)
IP协议的另外一个能力是路由,数据的传输需要通过很多的网关,路由器,交换机等很多网络设备,会形成很多条网络的路径,因此需要算法决定下一步该走哪里。
数据链路层:帮助数据进行跨网络传输。
不同网络中的通信,需要使用路由器,计算下一个要去的IP地址。路由器先计算出下一个目的地的IP地址,再通过ARP协议找到该目的地的MAC地址(唯一标识设备的),这样就知道这个IP地址是哪个设备的了。
物理层:把数据包转换成电信号,在物理介质中传输。
HTTP是超文本传输协议(HyperText Transfer Protocol)。
从协议,传输,超文本三个角度来解释。
HTTP使用了一种计算机能够理解的语言确立了一种计算机之间交流通信的规范,以及相关的控制和错误处理方式。而且HTTP是一个双向协议。比如我们搜索东西,浏览器是请求方,网站是应答方,浏览器把请求提交给网站,网站将数据返回给浏览器,实现了双向的传输。超文本就是不是普通文本的文本,比如文字,图片,视频的混合体,而且有超链接,能从一个超文本跳跃到另一个超文本。比如HTML。
概括:HTTP是一个在计算机里的两点之间双向传输文字,图片,视频等超文本数据的规范。
1xx:中间状态
2xx:访问成功的状态
200(200 OK):访问成功,如果不是HEAD请求,服务器会返回一个响应头,里面有完整的body数据。
204(204 No Content):访问成功,但是服务器返回的响应头没有body数据。
206(206 partial Content): 访问成功,服务器返回的响应头里面的body数据只是一部分,不是全部的。
3xx:需要重定向
301(301 Moved Permanently):永久重定向,当前客户端发送的请求资源已经不存在了,位置已经改变了,需要重新访问一个新的URL。
302(302 Found):临时重定向,当前客户端发送的请求资源,还存在,但是暂时需要访问另一个URL。
301和302的响应头里面都会有Location字段,Location字段含有当前资源的新地址,浏览器会自动跳转的。
304(Not Modified):当前访问的资源还在,不需要跳转,存在于重定向的缓存文件中。
4xx:客户端发送请求资源的问题
400(Bad Request):当前客户端发送的请求报文错误。
403(Forbidden):当前客户端发送的请求资源,服务器禁止访问。
404(Not Found):当前客户端发送的这个资源,服务器里面找不到。
5xx:服务器端的问题
500(Internal Server error):笼统的说明是服务器端的错误。
501(Not Implemented):目前客户端的请求,这个功能服务器不支持。
502(Bad Gateway):服务器作为中间的网关或代理的时候所返回的状态码,代表当前服务器没问题,但是后端服务器出问题了。
503(Service Unavailable): 当前网络繁忙,稍后再试。
Host字段:客户端发送请求时,用来指定服务器的域名。
比如:Host:www.A.com
Content—Length字段:服务器在返回数据的时候,会有Content—Length字段,表明本次回应的数据长度。
告诉浏览器,本次服务回应的数据长度是xxx个字节,后面的字节就属于下一个回应了。
Connection字段:最常用于客户端要求服务器使用TCP持久连接,以便于其他请求复用。
如果需要让服务器使用TCP持久连接,需要指定Connection首部字段的值为Keep-Alive。这样,一个复用的TCP连接就建立了,直到客户端或服务器主动关闭连接。
Content-Type字段:服务器告诉客户端,给客户端发送的数据格式。
Accept字段:客户端发送请求的时候,可以使用Accept字段来表示自己能接受哪些数据格式。
Content-Encoding字段:服务器告诉客户端,我给你发送的数据使用了什么压缩格式。
Accept-Encoding字段:客户端告诉服务器我能接受什么压缩方法。
Get方法是:请求从服务器获取资源,这个资源可以是文本,页面,图片视频等。
Post方法是:向指定资源提交数据,数据放在报文的body里,拼接好POST请求头。通过TCP协议发送给服务器。
安全和幂等:
HTTP中的安全指的是,请求的方法不会破坏服务器上的资源。
HTTP中的幂等指的是,多次执行相同的操作,结果都是相同的。
GET方法是安全并且幂等的,因为get方法进行的其实是只读操作,并不会修改任何服务器上面的资源。
POST方法是不安全且不幂等的,因为POST方法会新增或者修改服务器上面的资源,并且多次提交后会创建不同的资源。
优点:
1.简单:
HTTP的报文格式就是header+body,并且头部里面是key-value的形式,非常的简单,易于理解。
2.灵活和易于扩展:
HTTP里面的各种请求,URI/URL,状态码等都可以由程序员自己定义。HTTP也同时处于应用层,也就是说我们使用的人不需要去管它的下层是怎样变化的。比如HTTPS相比于HTTP来说,就是在HTTP和TCP层之间加了一个SSL/TLS安全传输层。
3.应用广泛和跨平台
HTTP的应用非常广泛,PC端的浏览器,还有手机上等各种软件,知乎,小红书,美团什么的。
缺点:
1.无状态和明文传输:
无状态指的是服务器不会去刻意记录HTTP的状态,这样的好处就是给服务器减轻了很多的负担,省下不少内存空间。但是这样不好的地方就是有些操作会比较麻烦,比如说一些关联性比较强的操作。比如登录淘宝账号登录,从选中商品开始,选定地址,然后到最后结账,这些过程中的每部操作服务器都不知道你是哪个账号,所以每一步请求都需要验证你的账号信息,这样就很不方柏霓,但是这个问题已经被cookie技术解决了,cookie标明了账号的信息,算是一个小标签。
明文传输对于操作者来说是比较方便的,因为在整个操作过程当中,我们能具体看见详细的信息。但是这样同时也造成了不安全的因素,这个过程中的信息传输等于是裸体的,我们有可能会泄露自己的账号信息。
HTTP/1.1整体在性能上要比HTTP/1.0强很多,但是也不能说是很完美。
长连接:
在1.0版本的时候,HTTP花费了很多时间来处理TCP的连接和中断,每发送一次请求都需要建立一次TCP连接,完成的时候再中断连接,这样开销太大,所以在1.1版本的时候,HTTP提出了长连接的思想,长连接就是建立一次TCP,并且使其持久连接,在连接过程中可以发送多次请求并且返回数据。直到有一方想要中断连接的时候才会中断。
管道网络传输:
因为实现了长连接,所以管道网络传输就有实现的可能性了,HTTP/1.1可以使客户端连续发送多个请求,并不是要求等第一个请求响应后的数据回来之后才可以进行下一次提交请求,而是可以一下子提交多个请求,但是在服务端那里还是按照请求的顺序依次回复,所以这也造成了一个问题:队头阻塞。
队头阻塞:当提交的第一个请求一直没有被服务端处理并且响应的时候,此时后面的请求也一直不会得到响应,由前面的请求没有被响应而引起多个请求阻塞的情况就叫做队头阻塞。
1.HTTP是超文本传输协议,信息传输是明文传输,因此会有不安全的因素在里面,而HTTPS很好的解决了这种情况,因为在HTTP层和TCP层之间加了一层SSL/TLS安全协议,所以使得信息能够加密传输。
2.HTTP连接的建立相对于比较简单,只需要完成TCP三次握手即可,但是HTTPS连接的建立,不光需要完成TCP的三次握手,还需要完成SSL/TLS的握手才能建立连接,进行加密报文传输。
3.HTTP的端口号是80,HTTPS的端口号是443。
4.HTTPS协议需要向CA申请数字证书,来验证服务器的可靠性。
HTTP存在以下的问题:
窃听风险:信息在通信链路上传播的时候容易被别人获取。
HTTPS解决这个问题是用的混合加密,保证了整个传输过程中不会被别人获取。
HTTPS采用的是对称加密和非对称加密结合的混合加密,在通信建立前采用非对称加密的方式交换“会话秘钥”,在通信过程中采用对称加密的“会话秘钥”的方式加密明文数据。
篡改风险:比如垃圾广告的植入。
HTTPS解决这个问题使用的摘要算法,如果通信内容被篡改的话那么就无法正常显示。
在明文从客户端发送之前,会通过摘要算法算出一个指纹,然后将指纹和明文一起加密发送到服务端,服务端根据相同的摘要算法算出来发送过来的明文,然后拿当前的指纹和客户端发来的指纹进行比对,如果是一样的,那么就代表没有被篡改。
冒充风险:比如逛的淘宝店铺是假的。
HTTPS解决这个问题使用的是数字证书,证明现在进行通信的服务端的可靠性。
客户端先向服务器端索要公钥,然后用公钥加密信息,信息传送到服务端后,服务端用私钥解密。而公钥是放在数字证书之中的(有CA机构颁发的),代表了可信度。
SSL/TLS协议建立的过程:四次握手
1.ClientHello
首先客户端向服务器法器加密通信请求,也就是ClientHello请求:
(1):客户端支持的SSL/TLS协议版本;
(2):客户端生产的随机数(Client Random),后面用来生产会话秘钥
(3):客户端支持的密码套件列表。Cipher Suites
2.ServerHello
服务器收到了客户端发来的ClientHello后,向客户端发出响应,ServerHello:
(1):确认SSL/TLS协议版本。
(2):服务器生产的随机数(Server Random),后面用来生产会话秘钥
(3):确认的密码套件,Cipher Suite
(4):服务器的数字证书。Server Certificate
然后发一个Server Hello Done
3.客户端的回应
客户端在收到服务器发来的数字证书之后,先验证一下数字证书的可靠性。
然后取出里面的公钥,用来进行加密。向服务器发送:
(1):客户端生成的一个随机数(pre-master key)。该随机数会被服务器公钥加密。
(2):加密算法改变通知,代表后面发送的消息都将用会话秘钥(对称加密算法)进行加密通信。
Change Cipher Spec
(3):客户端握手结束通知。同时也是让服务器做个验证,看看之前发的握手信息有没有被篡改过。
Encrypted Handshake Message
4.服务端的最后回应
在收到客户端发来的第三个随机数后,通过协商的加密算法,计算出本次通信的会话秘钥。然后最后给客户端发送一次信息:
(1):加密算法改变通知,代表后面发送的消息都将用会话秘钥(对称加密算法)进行加密通信。
Change Cipher Spec
(2):服务端握手结束通知。
Encrypted Handshake Message
整个SSL/TLS的握手阶段都结束了,接下来,客户端与服务器进入加密通信,完全是使用普通的HTTP协议,只不过用会话秘钥加密内容。
非对称加密:在通信建立之前,也就是第二次客户端发送的那个随机数会被公钥加密,这个时候的加密是非对称加密。
对称加密:在通信建立之后,客户端和服务端都发出加密算法改变通知后,代表后面我们要用对称加密的方式进行通信了,加密算法改变通知,也就是说的由非对称加密改成对称加密。
HTTP/1.1 相比 HTTP/1.0提高了什么性能?
使用了TCP长连接并且支持管道网络传输。
HTTP/2相比HTTP/1.1提高了什么性能?
1.头部压缩:
HTTP/2是基于HTTPS的,所以安全性是有保障的。HTTP/2会压缩头(Header),如果同时发出多个请求,并且多个请求的头部是一样的,那么协议会帮助消除重复的部分。
2.二进制格式:
HTTP/2不再像HTTP/1.1里的纯文本形式的报文,格式改变成了二进制的格式,头信息和数据体都是二进制,并且统称为帧,头信息帧和数据帧。增加了数据传输的效率。
3.数据流:
HTTP/2的数据包不是按顺序发送的,因此要给数据包做标记,指出它属于哪个回应。客户端可以指定数据流的优先级,优先级高的请求,服务器就先响应。
4.多路复用
HTTP/2是可以在一个连接中并发多个请求或回应,而不用按照顺序一一对应。解决了队头阻塞问题。
5.服务器推送:
改善了传统的“请求-应答”工作模式,服务端不再是被动地响应,也可以主动向客户端发送消息。
HTTP/3相比HTTP/2提高了什么性能?
HTTP/2会发生丢包现象,当发生丢包现象,那么在一个TCP连接中的所有HTTP请求都必须等待丢了的包重新传回来。
那么HTTP/3解决了这个问题,HTTP/3将TCP换成了UDP,UDP虽然是不可靠传输,但是基于UDP的QUIC协议可以实现类似的可靠传输。
QUIC将之前HTTPS的六次握手缩减到3次握手了。TLS也成了1.3版本,头部压缩算法也变成了QPack。
跟SSL/TLS握手过程一样。
RSA密钥协商算法的缺陷就是不支持前向保密,服务端是通过私钥来解密得到客户端发来的随机数的,但是如果私钥泄露了,那么就代表所有加密的报文都会被破解。
现在大多数使用的是ECDHE密钥协商算法。
在第二次握手后开始不一样,也就是服务端向客户端发送Server Hello之后,在发送完数字证书之后,还会发送Server Key Exchange。
在这个过程中,服务器选择好了:
椭圆曲线(name_curve),包括椭圆曲线基点G,会公开给客户端。
生成随机数作为服务端椭圆曲线的私钥,保留在本地。
根据基点G和私钥计算出服务端的椭圆曲线公钥,这个会公开给客户端。
第三次握手:
客户端这边也会生成一个随机数作为客户端椭圆曲线的私钥,然后再根据服务端前面给的信息,生成客户端的椭圆曲线公钥,然后用Client Key Exchange消息发给服务端。
然后发送加密算法改变通知。
然后发送Encrypted Handshake Message,握手结束通知,让服务端验证一下之前发送的消息有没有被篡改。
第四次握手:
发送Change Cipher spec和Encrypted Handshake Message。
不同的点的概括:
1.RSA握手是不支持前向保密的,但是ECDHE支持前向保密。
2.使用RSA密钥协商算法,是必须要完成TLS的四次握手之后,才能进行应用数据传输。但是使用ECDHE算法,客户端可以不用等服务器的最后一次TLS握手,就可以提前发出加密的HTTP数据,节省了一个消息的往返时间。
3.使用ECDHE,在第二次握手中有Server Key Exchange消息,在第三次握手中有Client Key Exchange消息。
1.尽量使用ECDHE,不要使用RSA。ECDHE又安全,又能减少一个消息往返的时间。因为完成前三次握手之后就可以进行应用数据的加密传输。
2.TLS协议升级,升级到1.3,握手只需要一个RTT,把Hello和公钥交换两个消息合并成了一个消息。Client Hello里面带上了支持的椭圆曲线,以及这些椭圆曲线的公钥。Server Hello选定一个,然后同时也带上服务器这边的公钥。只支持ECDHE密钥协商算法。
TCP是面向连接的,可靠的,基于字节流的传输层通信协议。
1:TCP是需要先建立连接再传输数据的,而UDP不需要建立连接,直接传输数据。
2:TCP是一对一的两点间服务。UDP支持一对一,一对多,多对多的通信。
3:TCP传输的数据可以做到无差错,不丢失,不重复,而UDP是不可靠传输,尽最大努力交付数据。
4:TCP有拥塞控制和流量控制机制,保证数据传输的安全性,但是UDP没有,即使网络拥堵,也不会影响发送数据的速度。
5:TCP首部长度比UDP要长,开销会稍微多一些。
6:TCP是流式传输,无边界,UDP式一个包一个包发送,有边界。
7:TCP的数据大小如果大于MSS,那么需要在传输层进行分片,目标主机收到后,也会在传输层组装分片,如果有哪个分片丢失,就只需要重新传输那个分片就可以。但是UDP的数据大小如果大于MTU,也需要分片,但是是在IP层进行分片,目的主机也同样在IP层进行组装,但是如果有丢失的分片,那么就会将所有的分片都全部重新传输一次。
应用场景:
TCP:FTP文件传输,HTTP和HTTPS,但是高版本的HTTP不再使用TCP进行传输,而是UDP,比如HTTP/3。
UDP:包总量比较少的通信,比如DNS,SNMP等。视频,音频通信,广播通信。
服务端和客户端一开始都处于CLOSED状态,然后服务端主动监听某个端口,处于LISTEN状态。
三次握手的第一个报文SYN报文:客户端会随机初始化序号(client_isn),将这个置于TCP首部的“序号”字段中,同时把SYN标志位置为1,表示SYN报文。将SYN报文发送给服务端,表示像服务端发起连接,这个报文不包含应用层数据,然后客户端处于SYN-SENT状态。
三次握手的第二个报文SYN+ACK报文:服务端收到客户端的SYN报文之后,首先服务端也随机初始化自己的序号(server_isn),将这个置于TCP首部的“序号”字段中,然后将TCP首部的“确认应答号”字段填入client_isn+1,同时把SYN和ACK标志位置为1,然后将这个报文发送个客户端,该报文也不包含应用层数据,然后服务端处于SYN-RCVD状态。
三次握手的第三个报文ACK报文:客户端最后向服务端发送一个报文,首先将ACK标志位改为1,然后将“确认应答号”字段填入“server_isn+1”,然后发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于ESTABLISHED状态。
服务器收到客户端的应答报文后,也进入ESTABLISHED状态。
只有第三次握手可以携带数据,前两次握手都不可以携带数据。
TCP建立连接时,通过三次握手能够防止历史连接的建立,减少双方不必要的开销,能帮助双方同步初始化序列号。
不使用两次握手:如果网络拥堵了,那么就代表发送一个SYN,就会期待回复一个ACK,但是很多的SYN拥堵了,对于客户端来说,没有收到ACK报文,那就会重复发送SYN报文,那么服务端这里,由于没有第三次握手,所以不确定客户端是否收到了ACK报文,只能是来一个SYN就回复一个ACK,就建立一次连接,这样就会造成很大程度的资源浪费。
不适用四次握手:三次握手就是对于四次握手的简化,不需要第四次握手。
首先,MTU指的是一个网络包的最大长度,如果一个IP层有一个超过MTU大小的数据,那么这个数据就要被分成若干片小于MTU的片,然后再发送,这些若干片到了目标主机的IP层之后再进行重新组装,但是如果这其中有一个小分片在网络传输的过程中丢失了,目标主机发现传输过来的数据是不完全的就不会发送ACK给我们,这个时候由于IP层没有超时重传机制,而TCP层有超时重传机制,这时候TCP发现超时了,那么就会把所有的TCP头部+数据全部发送一遍,而这样效率是很低的。
如果我们使用MSS的大小来限制TCP报文的大小(TCP协议在建立连接的时候通常要协商双方的MSS值),当然加上TCP头部之后每个分片也是小于MTU的大小的。经过TCP层分片之后,如果一个TCP分片丢失,这样的话我们就只需要重新传输那个没有传输过去的分片就可以了,而不需要重新传输全部的分片。效率很高。
TCP断开连接是通过四次挥手的方式。
客户端首先向服务端发出FIN报文(TCP首部FIN字段标志为1的报文),然后客户端进入FIN_WAIT_1状态。
服务端在收到FIN报文之后,也会向客户端发出ACK应答报文(TCP首部ACK字段标志为1的报文),然后服务端进入CLOSED_WAIT状态。
客户端在收到ACK应答报文后,变为FIN_WAIT_2状态。
服务端会发FIN报文到客户端,然后服务端变为LAST_ACK状态。
客户端会再向服务端发出ACK应答报文,然后客户端转变成TIME_WAIT状态。
服务端在收到ACK报文之后,会变成CLOSED状态。
客户端在发出ACK应答报文后的2MSL时间后也会变成CLOSED状态。
主动关闭连接的一方,才有TIME_WAIT状态。
当客户端发出FIN报文的时候,代表客户端这边停止发送数据了但是可以接收数据,服务端这里数据还没有发送完成,所以不可能立马结束,先回复给客户端一个ACK应答报文。服务端直到数据发送结束之后,会发送一个FIN报文,代表服务端也不再发送数据了并且同意现在关闭连接,得到客户端回复的ACK后,进入CLOSED状态。
也就是说当服务端回复ACK报文的时候,并没有完成数据的传输,直到服务端向客户端发送FIN报文的时候,才代表服务端这边不再发送数据了并且同意关闭连接。
MSL是报文最大生存时间,而2MSL开始计时是在客户端收到了服务端FIN报文之后发送ACK报文给服务端的时候(转变为TIME_WAIT状态)。如果ACK报文没有发送到服务端,那么就会在2MSL时间之内收到服务端重新发送的FIN报文,但是如果没有在2MSL时间之内收到服务端重新发送的FIN报文,那代表ACK报文已经发送到服务端了,所以此时就可以进入CLOSE状态了。
占用着内存资源和端口资源,可能会导致新的连接无法建立。
服务端和客户端都初始化一个Socket,但是服务端的第一个Socket其实是用来监听的,监听端口和IP地址是否有客户端来连接。第二个Socket是调用accept方法返回的,这个Socket是用来和客户端进行数据传输的。
客户端connect成功返回是在第二次握手之后,服务端accept成功返回是在第三次握手之后。然后accept返回一个可以进行通信的Socket。
客户端在发出FIN报文的时候就调用了close方法,代表从现在开始,我不发送数据了,但是可以读数据,并且在数据的最后加上一个EOF文件结束符,然后进入FIN_WAIT_1状态。而后服务端读到了EOF文件结束符,于是返回ACK报文,进入CLOSED_WAIT状态,客户端收到了ACK之后会进入FIN_WAIT_2状态。当服务器把数据都发送结束之后,也会发送FIN报文给客户端,告诉客户端,我这边也同意断开连接了,这时候就调用了close方法,然后进入LAST_ACK状态。客户端收到了FIN之后,也会返回ACK报文给服务端,然后发送出去ACK报文之后,客户端开始计时,2MSL之内,如果没有回复,那么就进入CLOSE状态,而服务端是在收到ACK之后,进入CLOSE状态。
超时重传:
TCP会在以下两种情况发生超时重传:
数据包丢失
确认应答丢失
RTO是超时重传时间:
当RTO时间过短:有的包没丢失就重传了,造成网络堵塞。
当RTO时间过长:丢了好久了才重发,浪费时间,性能差。
所以其实,RTO的值略微大于报文往返RTT的值就行了。
快速重传:
TCP快速重传机制,不以时间为驱动,而是以数据驱动重传。
SACK方法:
在TCP头部的选项里面加一个SACK的东西。 告诉发送方哪些数据收到了哪些没收到。
D-SACK:
ACK丢包:
最后发送的ACK4000,代表我已经收到了4000以前的了,4000以前的都是正常收到的了,但是3000-3500我是属于重复收到的。
主要使用了SACK来告诉“发送方”有哪些数据被重复接收了。就是告诉发送方:您不用重新发送了,我已经收到了,只不过我回复您的ACK报文丢失了而已,但是您发的报文确确实实俺已经收到了!!!!
网络延时:
最后返回的ACK是3000,代表ACK已经到3000了,前3000个哥都收到了,但是1000-1500我是收到重复的数据了。
D-SACK的好处:
可以让发送方知道是自己的发出去的报文丢了,还是回复的ACK报文丢了。
可以让发送方知道是否出现了网络延迟的现象。
可以让发送方知道自己是否是重复发送了报文,而且可以知道重复发送了哪部分报文。
SACK跟D-SACK的区别就是:SACK是SACK数大于ACK数,代表有遗漏的中间部分。
D-SACK是SACK数小于ACK数,代表那部分SACK数是重复的。
有的时候我们在通信的过程中,不可能是我说一句然后你就要回复一句,我才能说下一句。
TCP中滑动窗口的意思其实是:我可以说好几句,然后你也可以回复我好几句,不一定是我说一句你答一句这种形式。
但是至于我最多一次性能说多少句这个事情,取决于窗口大小。
这种ACK600报文丢失也没有关系的,因为ACK700这个报文都发回来了,这就代表700之前都顺利接收到了,这种机制叫做累计确认or累计应答。
窗口的大小是由接收方来决定的,接收方告诉发送方,这是我的窗口大小,这是我的限度,你按照我的这个大小来发送数据就行了。如果你发送的这个数据大小超过我的窗口大小了,那我可能无法正常接收到数据了。
接收窗口的大小是约等于发送窗口的大小的。
糊涂窗口综合症:如果接收方太忙,来不及取走接收窗口里的数据,那么就会导致发送方的发送窗口越来越小。到最后就是接收方腾出几个字节的窗口,发送方就发送几个字节的窗口,这就叫糊涂窗口综合症。到后面就是发送的数据越来越小了,那这样其实开销就比较大了,因为头部占比等于是越来越高了。
怎么能让接收方不通告小窗口呢?
可以拿窗口大小来衡量,当窗口大小小于MSS和缓存空间的一半的时候,直接向发送方发送窗口大小为0。意思就是,发送方先不要发数据过来了。
等过一会儿,接收方处理了一些数据之后,窗口大小大于MSS或者接收方缓存空间有一半及以上可以使用了,就可以把窗口打开让发送方发数据过来了。
怎么避免让发送方发送很小的数据呢?
使用Nagle算法:(至少满足以下一条条件才可以发送数据,否则就一直囤积数据,知道符合条件)
1.要等到窗口大小或者数据大小大于MSS。
2.收到之前发送数据的ack回包。
可以在Socket设置TCP_NODELAY选项来关闭这个算法(关闭Nagle算法没有全局参数,需要根据每个应用自己的特点来关闭)。
拥塞控制和流量控制的问题:
拥塞控制和流量控制是两个事儿,流量控制是使发送方能够在接收方能接受的限制内发送数据,使用发送窗口和接收窗口这种滑动窗口(滑动窗口决定最大限度的情况下能发多少数据)来控制。拥塞控制是指网络中发生的事情,在网络通信环境中可能会出现拥堵,如果在拥堵的时候还继续大量发送数据包,那就可能导致数据包丢失等,这时候TCP就会继续重复传数据,但是这同时也会使得网络的拥堵情况加剧,进入恶行循环。而这种情况才和TCP的拥塞控制有关,TCP在拥堵的时候会选择降低数据的发送量来缓解网络的状况。
所以基本上来说拥塞控制的目的就是避免发送方的数据填满整个网络,为了调节和控制发送数据的量,定义了拥塞窗口的概念。
拥塞窗口和发送窗口的关系:
拥塞窗口和发送窗口的关系:拥塞窗口——cwnd是一个动态变化的量,会根据网络的拥塞程度而改变。当网络比较拥塞的时候,cwnd就比较小,当网络不拥塞的时候,cwnd就比较大。
cwnd和swnd(发送窗口)与rwnd(接收窗口)的关系是cwnd=min(swnd,rwnd)。
如何知道网络是否出现了拥塞呢:
总的来说,只要发送了发送方这边没有收到ACK回应报文,触发了超时重传机制,那就是网络出现了拥塞。
拥塞控制的控制算法:
拥塞控制主要的四个算法:
1.慢启动
当发送方收到一个ACK报文,拥塞窗口cwnd的大小就增加一。
慢启动算法发包的个数是指数性增长的。
但是慢启动算法并不是可以一直这样增长下去的。慢启动算法是有一个慢启动门限的ssthresh(slow start threshold)
当cwnd < ssthresh 时,使用慢启动算法。
当cwnd>=ssthresh时,使用拥塞避免算法。
2.拥塞避免
一般来说ssthresh的大小是65535字节,进入拥塞避免算法之后,它的规则就是:每当收到一个ACK的时候,cwnd增加1/cwnd。其实也就是每次增长1个cwnd。在拥塞避免中cwnd的增加不再是指数级的增加了,而是变成了线性的增加。
现在这样虽然增加的比较缓慢了,但是依然是慢慢的增加着,后面就会使得网络拥塞,然后发送方发送的报文开始丢失,于是出发超时重传机制,进入拥塞发生算法。
3.拥塞发生
当网络刚进入拥塞状态时,使用的算法。
这个拥塞发生算法是默认在超时重传机制下发生的。直接将慢启动门限ssthresh设置为cwnd/2,然后cwnd设置为1,也就是直接从1开始,让其进入慢启动状态。非常狠的拥塞发生算法。
在快速重传条件下的拥塞发生算法相对于来说温和的多,如果接收方在接收的时候发现丢了一个中间的包,那就会连续发送三个之前的ACK来提示发送方有丢失的报文,于是发送方就会快速的重新发一个,不必等待超时重传。
TCP觉得这种情况没那么严重,只是丢了一小部分而已,则ssthresh和cwnd变化如下:
cwnd=cwnd/2;
ssthresh=cwnd;
然后就进去快速恢复算法
4.快速恢复
进入快速恢复算法之后,首先把cwnd=ssthresh+3(意思是有3个数据包收到了),重传丢失的数据包(是在快速恢复算法中实现的快速重传),如果再收到重复的ACK了,那么cwnd+1;如果收到的新的ACK了,然后把cwnd变成ssthresh+3,也就说明了ACK确认了新的数据,进入拥塞避免状态。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。