前言
上篇我们讲了http,我们知道了http是基于tcp的,先来看张图:
http是应用层协议,tcp是传输层协议,http作为上层协议建立在tcp之上。当然你看到传输层协议还有一个兄弟叫udp,这家伙经常和tcp做比较,本篇不做讲述,想知道的可自行了解吧,好了下面让我们直接进入正文吧。
tcp
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议
传输就好比是我们买的快递通过交通工具传递到我们手上,交通工具就是tcp,交到我们手上tcp就完成了它的任务了,剩下的就是http的事了,传输层协议就是干这个的。
tcp这个东西如果真要深究,恐怕一时半会也拎不清。所以我们根据tcp的两大特点:面向连接、可靠的来聊聊tcp吧。本篇我们先来讲讲tcp面向连接的这个特点吧。
面向连接是什么?就是通讯双方要先建立一条连接通道。
说到面向连接,你想到了什么,对了,就是那个?那个?
鼎鼎大名的tcp三次握手!!
每次面试面试官没少问吧?就是下面这张图:
让我们形象化的说明三次握手吧,三次握手的过程可以用打电话来模拟:
1、客户端说:服务器老哥你好,我是客户端,你能听得到我吗?
2、服务器说:客户端老弟你好,我是服务器,我可以听到你,请问你可以听到我吗?
3、客户端说:服务器老哥,我可以听到你。
好了,建立连接了,让我们开始聊天吧…
报文结构
开始讲三次握手先,让我们先来看个东西:tcp数据报文
TCP报文是TCP层传输的数据单元,也叫报文段,可以看出一个完整的报文结构由报头和数据两部分组成的。
源端口
源计算机上的应用程序的端口号,占16位。
目的端口
目标计算机的应用程序端口号,占16位。
seq(Sequence Number)
32位序列号,它表示该报文段发送数据的第一个字节的编号,在 TCP 连接中,传输的字节流每一个字节都有个顺序编号seq,以此来保持传输的有序性。上面中SYN为1时,表示用于同步初始序列号(ISN)。
ack(Acknowledgment Number)
32位确认序列号,它表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。说白点就是接受方希望下一次发报文的时候发送方要发给我的序列号(seq)。
标志位
标志位指明该报文的行为,占用1位,本篇先讲下面四个标志位:
SYN
同步标志位,当SYN=1,表示发起新的连接。
ACK
确认标志位,只有当 ACK=1时确认号字段(ack)才有效。当 ACK=0 时,确认号无效,TCP 规定,连接建立后,ACK 必须为 1。
PSH
推送标志位,告诉对方收到该报文段后是否立即把数据推送给上层。如果值为 1,表示应当立即把数据提交给上层,而不是缓存起来。
FIN
标记数据是否发送完毕。如果 FIN=1,表示数据已经发送完成,可以释放连接。
选项:选项字段,长度可变,TCP 首部可以有多达40字节的可选信息,用于传递附加信息。
数据:本次报文携带的数据字段。
注明:窗口大小、TCP校验和、紧急指针字段不在本篇的讨论范围内。
状态说明
CLOSED:表示初始关闭状态
LISTEN:服务器监听状态(等待客户端的连接)
SYN_RECEIVED(SYN_RCVD):服务器接收到客户端的SYN
SYN_SENT:客户端已发送SYN
ESTABLISHED:表示连接已建立
上面了解了报文结构和tcp连接过程几种状态,再结合上面那张三次握手的图片,我们再来正式的理解下:
三次握手过程
1、第一次握手:客户端发送SYN到服务器,表示要请求建立连接,开始进入SYN_SENT状态。
2、第二次握手:服务器收到请求后,回复SYN + ACK到客户端,表示确认了客户端的请求,此时服务器进入SYN_RCVD状态。
3、第三次握手:客户端收到SYN + ACK包,向服务器发送确认ACK包,客户端进入ESTABLISHED状态,服务器收到请求后也进入ESTABLISHED状态,完成三次握手。
此时 TCP 连接成功,客户端与服务器开始传送数据。
说到这里。相信你也能和面试官扯皮了。你以为你说完了三次握手就行了?what?你还是太年轻了,这时候面试官肯定会来一句:为什么是三次握手?二次或者四次不行嘛?
为什么是三次握手?
1.确定通信双方是否具有可收发能力
嗯?如果是二次握手的话,你再看看上面那张三次握手图,
第一次握手的时候,客户端发送一个SYN包给服务器,第二次握手服务器回复了ACK+SYN给客户端,能收到服务器的确认回复这说明了对于客户端来说,客户端能确认了服务器的接收与发送的能力没问题。
但是如果只是两次握手的话,那么问题来了,没错,客户端是可以确认服务器有收发的能力,可是服务器能确认客户端有这种能力吗?不能确认了吧,因为没法得到客户端的确认回复,服务器也不知道发没发成功。
2.确定双方初始序列号
其实你看图就知道了,三次握手的过程其实就是在相互告知初始化序列号(ISN),并确定对方已经收到的过程。
如果只是两次握手,只有客户端的起始序列号能被确认,服务器的序列号则得不到确认。
呃。。。这个要怎么解释呢?我们知道tcp为了保持有序,报文头部需要依靠seq来保持有序,所以必须在建立连接时候双方协定一个初始序列号,后续通信都是依赖这个初始序列号,保证字节流上是有序的。
如果无法保持有序,可能出现数据丢失,或者乱序导致数据错误等一系列问题,下面没法玩了。
既然三次能到达目的,那为什么还要第四次呢?浪费资源不是?
最后说到底为什么需要三次握手,因为tcp要保持可靠啊,无论是确定双方是否有接收发送的能力还是字节流传输保持有序都算是tcp可靠的一个体现了吧。
总结
本篇介绍了tcp并且基于tcp面向连接的特点讲述了tcp的三次握手过程和三次握手的必要性,相信你也能和面试官扯皮了,所以你学废了么?下篇我们讲讲tcp的第二个特点可靠性吧,敬请期待!
作者简介: 一个不像程序员的程序员,专注于前端开发,偶尔也谈谈梦想。