TCP是面向连接的,可靠的,基于字节流的传输层协议。
连接
所谓连接其实是保证可靠性和流量控制的状态信息的总和,包括sokict,滑动窗口和序列号。
可靠性
tcp通过序列号,重传机制,滑动窗口等一系列控制机制保证数据的无重复,无丢失,有序的被接受端处理。
字节流
tcp的数据是基于字节流,因此是无边界,数据是可以无限大的,tcp可以通过分片机制将数据有序发送到接收端。
TCP的头部在无“选项”字段的情况下是20个字节。包括:
这里需要说明的是“选项”这个字段是用来辅助解决可靠性问题的,正是因为这个字段的长度是不确定的,所以需要“首部长度”这个字段来表示TCP头部的长度。
TCP是基于连接的,所以TCP在使用前必须先建立连接,TCP建立连接的过程是基于三次握手的。
至此,tcp连接建立完成,注意第三次握手是可以传输数据的。在这之前不能传输数据。
一般大家都会认为三次握手是为了保证客户端和服务端双方都能确认自身和接收端建立单向连接和保证自身能够发送和接受成功数据。
这样答本身也没有错,但是太粗化了。
既然握手是为保证连接的建立,那就要先知道什么是TCP连接。
TCP连接是保证可靠性和流量控制的状态信息的总和,包括socket,序列号,滑动窗口。
在这里这个序列号至关重要,是保证消息无重复,无丢失,有序的关键,因此这里其实就是为了保证序列号的同步。
客户端给服务端发送一个初始序列号,服务端回复syn+ack,就是告诉客户端序列号已经收到了并且把服务端的初始序列号发送给客户端,客户端收到后也要回复给服务端表示序列号已经收到,这样就能保证双方都能确保序列号同步。
但是这还不是最重要的原因,最重要的原因是防止历史连接初始化再次连接。比如有这样一种情况,客户端发送syn包给服务端,但是网络阻塞了,服务端没有收到,所以服务端也不会回复,客户端收不到回复就会重新发送syn包,但是就在这时候服务端接收到了第一个syn包,并且回复客户端,这个时候客户端会进行比对校验这是不是自己最新发送的syn回复包,如果不是的话就会给服务端发送rst包,表示要求服务端中断这个连接。这也是三次握手的意义所在。
如果说没有第三次握手,那么在发生上面的这个情况后,服务端就会为每个syn请求创建连接,连接是需要占用内存的,就会耗费很多的资源。造成资源浪费,所以三次握手很有必要。
那么四次握手是否可以呢?
四次握手的话也是可以的,四次握手其实就是客户端发送syn包给服务端,服务端回复ack包,服务端发送syn包给客户端,客户端回复ack包,三次握手中的第二次握手回复的是syn+ack包,所有相当于合并了四次握手中的中间两次,所以三次握手最好。
TCP是双向连接,所以两个方向上的连接都要断开。
在网络传输的世界里,有两个值是用来表示数据包失效的:
所以一般情况下MSL会大于TTL减为0所消耗的时间。
这里为什么是2倍的MSL呢?
因为当客户端接收到服务端的fin包后,会向服务端回复ack,但是客户端不知道这个ack是否发送成功了,所以客户端需要确认服务端接受成功后才能置为close状态,怎么确认呢,因为失败重传机制的存在,如果因为网络阻塞服务端没有收到ack,服务端会再次发送一次fin,一次ack包和再一次fin包就是2倍的MSL。MSL的计时是从收到fin包并且发送ack包开始的。
除了上面说的保证客户端的ack发送到服务端,并被正确接收,从而保证被关闭连接的一方可以正确关闭。
还能保证那些阻塞在网络中旧的连接,在端口又被复用的情况下,被接收到,这样就会发生数据错乱,而time_wait可以保证全部的网络中的连接被丢弃。
MSL默认是30秒。需要注意的是time_wait 的状态多了会占用内存资源和端口资源,所以不宜太多。
为什么要进行四次挥手?
tcp是双向连接,客户端发送fin包给服务端,服务端回复ack,只是客户端告诉服务端不再向服务端发送数据。
还需要服务端告诉客户端,服务端不再向客户端发送数据了,也就是服务端也要想客户端发送fin包,客户端也要给服务端回复ack包,这时候服务端和客户端才能进入close状态。
服务端在收到客户端发送的fin包并回复ack包后,服务端并不能马上向发送端发送fin包,因为此时可能还有连接在处理数据,必须等到数据处理完后才能向客户端发送fin包。
正因为这个原因,不能像三次握手那样把中间两次合并。
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://www.jmbhsh.com/baihuokuaixun/33768.html