tcp概述
TCP(Transmission Control Protocol)又叫传输控制协议,是面向连接的、可靠的、基于字节流的传输层通信协议。
- 面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;
- 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;
- 字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。
优点: 可靠,稳定。TCP的可靠性体现在传输数据之前,三次握手建立连接(四次挥手断开连接),并且在数据传递时,有确认,窗口,重传,拥塞控制机制,数据传完之后断开连接来节省系统资源。
应用场景: 对网络通信质量有要求时,比如:整个数据要准确无误的传递给对方,这往往对于一些要求可靠的应用,比如HTTP,HTTPS,FTP等传输文件的协议,POP,SMTP等邮件的传输协议,websocket协议等。
头部格式
我们先来看看 TCP 头的格式,标注颜色的表示与本文关联比较大的字段,其他字段不做详细阐述
序列号: 在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
确认应答号: 指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
控制位:
- ACK(Acknowledge character即是确认字符):该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。
- RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
- SYN(同步序列编号Synchronize Sequence Numbers):该位为 1 时,表示希望建立连接,需要同步序列号,并在其「序列号」的字段进行序列号初始值的设定。
- FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。
3次握手4次挥手
一个可靠连接肯定会有以下三个过程:创建连接、 数据传输、 终止连接
创建连接
这里就是常说的‘三次握手’,其实完全可以用常识来理解这个过程,两个人之间如果想建立一个通信,至少需要有三次对话才能保证通信的可靠。举个栗子,相信大家打游戏的时候都跟队友语音过。
{timeline}
{timeline-item color="#19be6b"}
A:听得到吗?
建立连接,客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认
{/timeline-item}
{timeline-item color="#ed4014"}
B:我听到了,你能听到我说话吗?
服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
{/timeline-item}
{timeline-item color="#ed4014"}
A:ok,我能听到~
客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
{/timeline-item}
{/timeline}
数据传输
{timeline}
{timeline-item color="#19be6b"}
A:我给你发个一堆东西,你按照顺序拼好
{/timeline-item}
{timeline-item color="#ed4014"}
B:收到了
发送的文件其实被拆成一个一个的小块,seq(Sequence Number)的作用是序列号,让服务器端能拼回来。
{/timeline-item}
{/timeline}
终止连接
当数据传输完毕之后,就要终止连接了,也就是 ‘四次挥手’
{timeline}
{timeline-item color="#19be6b"}
A:我要下了,你有什么想对我说的吗?
主机1(可以使客户端,也可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
{/timeline-item}
{timeline-item color="#ed4014"}
B:等等,让我说完 xxxxx……
主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2同意‘关闭’,但是要等一下,因为这里可能还有数据没有接受完
{/timeline-item}
{timeline-item color="#ed4014"}
B:好了,我说完了。
主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;
{/timeline-item}
{timeline-item color="#ed4014"}
A:那拜拜啦~
主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。
{/timeline-item}
{/timeline}