1.TCP概论
1.1.什么是TCP
为了保证所有设备能相互通信,从而建立了一张互联互通的计算机网络,在这张大网里,两台计算机之间想进行通信就像寄快递,整个快递一定要有固定且通用的格式,这样在传递过程中才能进行一层一层的识别和传递,比如包裹上有信封、信封上有邮编、发送人信息、接收人信息,包裹里面的纸箱上会有商品的相关信息,然后最里面是商品。
这些层层固定的格式就是网络协议,有的协议保证数据不丢失、不乱序、有的层处理网络异常等等等等,所有层一起联合起来一起保证通信的可靠与通畅。
TCP协议属于这些分层里面的传输层,主要负责的职责是保证通信的可靠性。TCP协议规定了一些校验字段,通信双方以报文中固定的这些字段来进行可靠的通信,从而保证了数据的可靠性、不会乱序等。TCP协议建立起来这种两点间可靠的、面向连接的通信通道,在逻辑上给人一种像直接连接在一起一样进行通信的感觉。
所以TCP常常被总结为,面向连接的,点对点通信。建立这条逻辑连接则是TCP的核心。
1.2.TCP连接的建立过程
TCP是通过三次握手,即三次报文交换来建立连接的。
第一次:发送同步请求,SYN置1,随机生成一个序列号a。
第二次:回复,ACK(值为前一个包的序列号a+1),已经收到数据包。同时生成自己的序列号b,发送SYN=1,收到请回复。(SYN位只会出现两次,因为三次握手,只需要两次应答。)
第三次:序列号a+1,生成ACK(b+1)。
1.3.TCP的传输过程
TCP连接建立过程中生成的那个序列号会在后续的传输过程中被继续使用,基于该序列号来控制通信的有序性。
在TCP连接建立后,数据发送方会将要发送的数据划分为较小的报文段,并为每个报文段分配一个序列号,序列号单调递增。数据接收方通过检查序列号来确定接收到的数据的顺序。TCP协议要求数据接收方必须按照序列号的顺序将数据重新组装成完整的数据流。
同时,TCP协议还使用确认机制来确保数据的完整性。数据接收方会发送确认报文段(ACK)给数据发送方,其中包含确认号(Acknowledgment Number),表示已成功接收到的数据的最高有效序列号。数据发送方会根据收到的确认号来确定哪些数据已经被成功接收,从而维护数据的有序性和完整性。
如果数据发送方没有收到确认报文段,或者接收方检测到数据包的丢失、损坏等情况,TCP协议会进行重传,确保数据的可靠传输。
1.4.TCP连接的释放过程
TCP是通过两次握手来释放连接的,也就是A对B拆一次线,B对A拆一次线。
- 发送关闭请求: 当一方决定关闭连接时,它会发送一个TCP报文段,其中包含一个标志位FIN(Finish)设置为1,表示希望关闭连接。这个报文段被发送给对方,进入FIN_WAIT_1状态。
- 确认关闭请求: 接收到关闭请求的一方会发送一个确认报文段,其中ACK(Acknowledgment)标志位被设置为1,同时将确认序号设置为收到的序号加1。这个报文段被发送给对方,进入CLOSE_WAIT状态。
- 发送关闭确认: 接收到关闭请求的一方会继续处理未完成的数据传输,直到完成后发送一个关闭请求。该关闭请求的报文段中的FIN标志位被设置为1,并附带一个确认号,表示已经确认了对方发送的关闭请求。这个报文段被发送给对方,进入LAST_ACK状态。
- 确认关闭确认: 接收到关闭确认的一方会发送一个确认报文段,其中ACK标志位被设置为1,同时将确认序号设置为收到的序号加1。这个报文段被发送给对方,进入TIME_WAIT状态。
2.JAVA中的TCP
JDK中有专门支持网络通信的模块,Socket是对TCP/IP通信过程的一个抽象,它将TCP/IP协议里面复杂的通信逻辑进行 封装,对用户来说,只要通过一组简单的API就可以实现网络的连接和通信。
博主有一篇博文详细介绍了JDK中的网络通信,可以异步看一下:
3.TCP带来的一些性能问题
1.无法准确知道数据包什么时候接收完
很显然TCP虽然提供了序列号来控制数据的有序性,但是我们无法知道数据什么时候能接收完整。比如请求一次后端的接口,随着传参的不同,数据的大小肯定是不固定的,到底要多少个数据段才会收完,接收方是不确定的。所以接收方只能一直去读IO,直到读完为止。
accept的socket并不知道其数据包是否已经收完,很可能出现因为数据包没有收完,还需要阻塞在原地等待IO继续收数据包的情况,本来分过来的CPU时间片是希望当前线程向下执行代码,结果用去继续IO收数据包去了,IO操作对于CPU而言很慢,时间片的利用率会很低,耗时会很严重。
这也就促成了后面NIO以事件响应的方式来启现场处理请求的模式。
2.连接过程过于耗时
一条TCP连接的建立需要客户端和服务器来回三次报文交换,很明显这是一个很耗时,很重的过程,为了避免来回建立TCP造成的性能损耗,很多对性能有要求的场景纷纷都开始支持“长连接”。HTTP2开始HTTP协议标准中开始支持长连接,在HTTP头部设置Connection: keep-alive,服务器和客户端会协商保持连接的状态。这样,在同一个TCP连接上可以进行多次请求和响应,实现长连接的效果。
Web服务器,诸如tomcat之类的,会用线程去托管每个socket,使得socket可以保持长时间的打开。
3.单台机器TCP连接具有有限性
TCP 连接的信息一般存储在服务器的内核空间中。那么所谓的TCP连接有限,其实就是指的IO缓冲区有限导致的并发的TCP有限,另一个维度是说内核段存储空间有限,有两个维度。