提起TCP,它的体系太过庞大了(足以写了一套书TCP/IP详解卷一,卷二,卷三),以前只买了第一卷阅读,由于我们是码农级别的人,很难真正的研究透,就好比汽车,大大大部分人只会开,但让他弄懂发动机原理甚至做出模型来就难了,我们关注下tcp为什么要三握手四挥手,这很重要(特别是java操作数据库时印象深刻),其实其它也很重要,码农们要是有时间和精力,可以精读这套书,写写心得体会,最好是能写个案例。
说正题,百度百科是这样解释的: TCP/IP协议,TCP提供一种“”可靠“”的“”面向连接“”的字节流传输层服务,面向连接意味着两个使用TCP的应用(通常是一个客户端和一个服务端)在彼此交换数据之前必须先建立一个·TCP连接。这一过程与现实场景的打电话相似,先拨号,等待对方接听后,才能通话。
TCP 为提供可靠性传输,实行“顺序控制”或“重发控制”机制。此外还具备“流控制(流量控制)”、“拥塞控制”、提高网络利用率等众多功能,不同于UDP
TCP有以下特点:
-
TCP充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制;
-
此外,TCP 作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费;
-
根据 TCP 的这些机制,在 IP 这种无连接的网络上也能够实现高可靠性的通信( 主要通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现)。
它在OSI七层协议与TCP/IP四层协议的位置如下图:
在TCP/IP协议中,TCP处在传输层,TCP数据被封装在IP数据报中,如下图:
TCP首部数据格式如下图:
TCP首部:源端口、目标端口、序列号、确认序号、数据偏移、保留、控制位、窗口大小、校验和、紧急指针、选项、填充。
控制位:8位。CWR、ECE、URG、ACK、PSH、RST、SYN、FIN
CWR:为1 就通知对方已将拥塞窗口缩小
ECE:为1 就通知对方这边的网络有拥塞
URG:为1 包中有需要紧急处理的数据
ACK(Acknowledgement):为1 确认应答的字段变为有效
PSH(PUSH):为1 表示要将收到的数据立刻传给上层应用协议
RST:为1 表示TCP连接出现异常必须要强制断开
SYN(Synchronize Sequence Numbers):为1 请求建立连接
FIN:为1 请求断开连接
seq:序列号
ack(注意和大写的·ACK区别):Acknowledge number确认号码
TCP连接是通过三次握手进行初始化的。又由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式,所以需要四次挥手关闭连接。
三次握手(Three-way Handshake)(重点):
三次握手, 是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个报文。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时, 将触发三次握手。
三次握手过程的示意图如下:
图1 三次握手建立连接
详细说明:
第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,保存在TCP首部的序列号(Sequence Number)字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端确认。
第二次握手:服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。
第三次握手:客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
四次挥手(重点):
四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发。
由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。
下面来看看四次挥手的流程图:
图2 tcp四次挥手
中断连接端可以是客户端,也可以是服务器端。
第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。
第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
建立连接时因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。所以建立连接只需要三次握手。
由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式。
这就意味着,关闭连接时,当Client端发出FIN报文段时,只是表示Client端告诉Server端数据已经发送完毕了。当Server端收到FIN报文并返回ACK报文段,表示它已经知道Client端没有数据发送了,但是Server端还是可以发送数据到Client端的,所以Server很可能并不会立即关闭SOCKET,直到Server端把数据也发送完毕。
当Server端也发送了FIN报文段时,这个时候就表示Server端也没有数据要发送了,就会告诉Client端,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。
暂时就写这么多,以后慢慢补充,TCP/IP协议族博大而精深