TCP协议的三次握手和四次分手
TCP三次握手阶段
三次握手总述
1. 为什么建立连接
tcp是一个可靠的传输机制,可靠在于每次收到一个数据都会相应的收到一个确认包之后才会将缓冲区的内容给删除掉,否则过一段时间就会重传。
建立连接就像是侦察兵侦查道路一样,我先看看这条路能不能走,如果能走,后面的大部队就跟上来了,如果不能走,后面的大部队就等着我继续侦查。
2. 为什么要用标志位syn?
案例一: 没有标志位syn的对话
客户端:嗨,服务器
服务器:你恐怕是傻子吧,给我发这个干嘛呢!!
案例二: 有标志位syn的对话
客户端:嗨,服务器,我们开始连接吧
服务端:好的,可以
syn: 告诉服务端发送这条数据的客户端想通过三次握手建立tcp连接
3. 为什么要用标志位seq,ack
案例:
客户端:嗨,服务器,这是我要跟你连接的第一条数据。 seq=1,syn=1
服务器:一看序列号是1,syn是1,是想和我连接的,因此给他回复:好的,我已经收到你的数据了,我们可以连接了。 seq=10,ack=2此时的ack是收到数据的seq号加上1
客户端:一看ack是2,就是我上一条数据的序列号加1,看来服务端已经同意我要连接了,因此回复:大哥,那我们开始发送数据吧。 seq=2,ack=11,此时三次握手建立成功
seq:用来表示当前数据包的标号
ack: 它的值是收到数据的seq值加上一,用来告诉对方我收到了你的数据包。
4. 状态机是什么意思?
(1)我们会看到在图的左右两边有syn_send,syn_listen等字样,这个指的是在客户端或者服务端收到某条信息之后会进入到哪个状态中。这个状态就是tcp的状态机。
(2)为什么要有这个状态机,因此tcp的连接或者断开都是有一个明显的过程中,对于每个过程都表示一个状态对于以后的排查问题是很重要的,例如:当前有大量的tcp状态是处于syn_rvcd,这很明显是有问题的。
5. 为什么要用三次握手去建立连接,一次不行吗?
之前已经说过,tcp的可靠机制是由于会发送确认包,因此在建立连接的时候我必须要确认我发送的信息你是否收到了,如果没有收到,我是会继续发送的。
案例:
客户端:嗨,大哥,我们连接吧?(如果就这样就完了,那我客户端怎么知道我这条连接的数据到底发送成功没有呢?因此服务器必须给我回复信息,也就是第二次连接了)
服务器: 行,我们连接吧!(如果这样就完了,那么服务器就会想了,这条数据客户端到底收到了没有,没有收到咋办,真让人头疼,因此大哥跟你小弟说话了,不管怎样,你的表个态,这就有了第三次连接了)
客户单:好嘞,大哥,小弟知道了,我们开始发送数据吧。 (至此真正的连接才算完成)
第一阶段:
注意:
连接都是从客户端开始的。
1. 没有客户端连接的时候
服务端:服务端首先处于syn_listen状态,也就是在监听客户端的连接。
客户端:客户端在没有收到服务器给我回复的确认包之前一直都处于syn_client状态。
2. 客户端发送:seq=1,syn=1的报文之后
服务端:服务端一旦接收到syn=1的报文之后,状态就会变成syn_rcvd
3. 服务端发送:seq=10,ack=2的报文之后
客户端:客户端进入established的状态,并且会发送一个确认报文,当服务端接收到报文之后也会变成established状态。
概念:半连接池
问题:现在有100个客户端同时连接过来了,而我的服务器1s中只能处理创建一个进程处理一个连接
半连接池:现在有前5个连接
服务器:在一秒中的时候创建了一个进行从半连接池中取了一个连接进行回复,此时那剩余的95个客户端有一个又进入了半连接池中等待连接,等第二秒的时候服务器重新创建了一个进程从半连接池中得到了一个连接,此时剩余的94个客户端中有一个也进入了半连接池中。
为什么要用半连接池呢?
为了防止某一时间段大并发的访问网站从而导致服务端崩溃掉。
对比
没有半连接池: 来了100个客户端,我就要维持100个客户端当前的状态,来了1000个,我就要维持1000个,那要是来了1亿个请求呢?怎么办,内存可能就要爆掉了。
有半连接池:规定了半连接的数量是100,如果来了1000个连接,不好意思,我现在服务器很忙,你得等一会,等我半连接池的连接被处理了我才能来放你们进来。
三次握手正常状态
客户端常见的状态
established: 从你发送的那一刻起到服务端响应的这段时间是非常短的,因此在大部分的情况下我们看到的都是established状态。
服务端常见的状态
syn_listen: 代表的是此时服务器是没有客户端来进行访问的
established: 三次握手如果没有什么问题,三次握手的状态是很快的,因此大部分的状态也是此状态。
三次握手异常状态syn_rcvd
TCP四次挥手阶段
四层挥手总述
1. 为什么是服务端先发起的断开连接请求?
对于客户端而言,我们一般是向服务器索求数据的,因此当服务器端把我们所需要的数据完全的发送给客户端之后,为了提升工作效率,就会迫不及待的关掉连接,然后去做处理其他的请求。因此一般我们看到的都是服务器端先发送一个fin标志位为1的数据包表示服务器端想断开连接。
2. 标志位FIN
和三次握手的SYN一样,此处的FIN就是为了告诉对方我想断开连接
3. 为什么要用四次挥手去断开连接?
因为在tcp建立连接之后数据的交互是双向的,因此tcp连接也给我们虚拟出了两个通道,一个是server--->client的通道,一个是client--->server的通道
当我们的服务器数据传输完成之后server--->client的通道已经没有存在的必要的了,因此server发送fin断掉此通道的连接,但是此时的client--->server还要给server端发送ack确认报文,因此此时这个client-->server的通道还不能断开
当服务器收到了ack报文之后,也就代表着client--->server的的通道已经没有必要在存在了,因此客户端向服务端发送断开请求,服务端发送一个ack确认断开之后就可以断开了。
4. 当出现了大量的TIME_WAIT状态代表的是出现了高并发的请求。
UDP与TCP的区别
1. TCP要建立连接,UDP不需要
2. TCP可靠, UDP不可靠,是因为有确认包的原因
3. TCP效率低,UDP效率高,一是因为连接的问题,二是因为确认包的问题,但主要的还是因为确认包的问题
4. TCP适合用在较大的数据量,因为UDP的字节一旦超过512,就极易丢失
示例:如下图访问如下网址就会出现下面的信息https://www.cnblogs.com/huwentao/p/9845379.html ,接下来以这个网址为例来说明一下浏览器究竟是得到这个数据的
URL的解释
url:统一资源定位符
三部分组成
1. 协议 https://
2. 域名 www.cnblogs.com:80 此处隐藏了端口,web服务的客户端为80
3. 路径 /huwentao/p/9845379.html
步骤一:首先通过域名得到对应的ip地址
首先通过域名得到对应的ip地址
1. 当前的浏览器就是一个socket客户端,此socket客户端具有当前主机的ip,端口,mac,DNS地址等信息
2. 浏览器的socket客户端 通过本机获得得DNS服务器IP地址然后加上53端口去链接DNSsocket服务端
3. 然后通过UDP将www.cnblogs.com发送到dnssocket服务端
4. DNS将解析到的地址返回到浏览器的socket客户端
因此我们得到了以下的url地址:
1. 协议 https://
2. 域名 101.37.255.65:80 此处隐藏了端口,web服务的客户端为80
3. 路径 /huwentao/p/9845379.html
步骤二:通过解析的ip加端口获得一个tcp连接
通过解析的ip加端口获得一个tcp连接
1. 通过101.37.255.65:80建立一个tcp的连接
2. 将数据 /huwentao/p/9845379.html 通过https协议封装,然后封装端口,ip,mac等信息之后发送到客户端
3. 获得当前服务器上的一个文件
4. 通过tcp连接源源不断的往客户端发送
5. 发送完了之后立马发送一个FIN标志位的信息断开连接
6. 客户端发送ack确认包断开连接
7. 客户端再发送FIN标志位断开上层通道
8. 收到服务器端的ACK报文之后断开tcp连接
步骤三:将收到的文件已html的形式展现的浏览器上面