龙空技术网

【干货】TCP/IP协议

南秋同学 55

前言:

现时我们对“tcpip协议java”大约比较关注,大家都需要学习一些“tcpip协议java”的相关知识。那么小编同时在网络上搜集了一些有关“tcpip协议java””的相关知识,希望我们能喜欢,咱们快快来学习一下吧!

TCP/IP协议

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前需要建立连接,传输完毕后需要断开连接,客户端在收发数据前要使用connect()函数与服务器建立连接,建立连接的目的是保证IP地址、端口、物理链路等准确无误,为数据的传输开辟通道。

TCP建立连接时需要传输三个数据包,俗称三次握手(Three-way Handshaking)。

TCP数据包结构

如图所示:

其中:

序号:SEQ(Sequence Number)序号占32位,用于标识从计算机A发送到计算机B的数据包序号,计算机发送数据时对此进行标记。确认号:ACK(Acknowledge Number)确认号占32位,客户端和服务端都可以发送,ACK=SEQ+1。标志位:每个标志位占用1Bit,共有6个,分别为URG、ACK、PSH、RST、SYN、FIN。具体含义:

URG:紧急指针(urgent pointer)有效。ACK:确认序号有效。PSH:接收方应该尽快将这个报文交给应用层。RST(Reset):重置连接。SYN(Synchronization):建立一个新连接。FIN(Finish):断开一个连接。
建立连接(三次握手)

使用connect()建立连接时,客户端与服务端会相互发送三个数据包。

如图所示:

客户端调用socket()函数创建套接字,因为此时还未建立连接,所以套接字处于CLOSED状态,服务端调用listen()函数,套接字进入LISTEN状态,开始监听客户端请求。

建立TCP连接主要步骤:

1)客户端调用connect()函数,TCP协议会组建一个数据包,并设置SYN标志位,表示该数据包用于建立同步连接,同时生成一个随机数字1000,填充序号(SEQ)字段,表示该数据包的序号,完成这些工作后向服务端发送数据包,客户端进入SYN-SEND状态。2)服务端收到客户端数据包,检测到设置了SYN标志位,则判定是客户端发送的建立连接请求包。服务端组建一个数据包,设置SYN和ACK标志位,SYN表示该数据包用于建立连接,ACK用于确认收到客户端发送的数据包:服务端生成一个随机数2000(2000和客户端数据包没有关系),填充序号(SEQ)字段。服务端将客户端数据包序号(1000)加1,得到1001,并用该值填充确认号(ACK)字段。服务端将数据包发出,进入SYN-RECV状态。3)客户端收到服务端数据包,检测到设置了SYN和ACK标志位,判定是服务端发送到确认包,客户端检测到确认号(ACK)字段值是否为1001(1000+1),是则说明连接建立成功,此时,客户端继续组建数据包,设置ACK标志位为2001(服务端发送的数据包序号+1),表示客户端正确接收了服务端发送的确认包,发送数据包到服务端。4)服务端接收客户端数据包,检测到设置了ACK标志位,判定是客户端发送的确认包,检测确认号(ACK)字段值是否为2001(服务端数据包序号+1),是则说明连接建立成功,服务端进入ESTABLESED状态。

至此,客户端和服务端均进入了ESTABLISED状态,建立连接成功,可以收发数据了。

断开连接(四次挥手)

建立连接非常重要,它是数据正确传输的前提;断开连接同样重要,它让计算机释放不再使用的资源。如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧。

如图所示:

建立连接后,客户端和服务器都处于ESTABLISED状态。这时,客户端发起断开连接的请求。

断开TCP连接主要步骤:

1)客户端调用close()函数后,向服务器发送FIN(FIN是Finish的缩写,表示完成任务需要断开连接)数据包,进入FIN_WAIT_1状态。2)服务器收到数据包后,检测到设置了FIN标志位,知道要断开连接,于是向客户端发送“确认包”,进入CLOSE_WAIT状态。注意:服务器收到请求后并不是立即断开连接,而是先向客户端发送“确认包”,告诉客户端,服务端需要准备一下才能断开连接。3)客户端收到“确认包”后进入FIN_WAIT_2状态,等待服务器准备完毕后再次发送数据包。4)服务器准备完毕,可以断开连接,于是再主动向客户端发送FIN包,告诉客户端可以断开连接,然后进入LAST_ACK状态。5)客户端收到服务器的FIN包后,再向服务器发送ACK包,告诉服务端断开连接,然后进入TIME_WAIT状态。6)服务器收到客户端的ACK包后,断开连接,关闭套接字,进入CLOSED状态。

客户端为什么最后一次发送ACK包后进入TIME_WAIT状态,而不是直接进入CLOSED状态关闭连接?

TCP是面向连接的传输方式,必须保证数据能够正确到达目标机器,不能丢失或出错,而网络是不稳定的,随时可能会毁坏数据,所以机器A每次向机器B发送数据包后,都要求机器B确认,回传ACK包,告诉机器A已经收到数据包,这样机器A才能知道数据传送成功了。如果机器B没有回传ACK包,那么机器A会重新发送,直到机器B回传ACK包。

客户端最后一次向服务器回传ACK包时,有可能会因为网络问题导致服务器收不到,服务器会再次发送FIN包,如果这时客户端完全关闭了连接,那么服务器就收不到ACK包了,所以客户端需要等待片刻、确认对方收到ACK包后才能进入CLOSED状态。

数据包在网络中是有生存时间的,超过这个时间还未到达目标主机就会被丢弃,并通知源主机。这称为报文最大生存时间(MSL,Maximum Segment Lifetime)。TIME_WAIT要等待 2MSL才会进入CLOSED状态。ACK包到达服务器需要MSL时间,服务器重传FIN包也需要MSL时间,2MSL是数据包往返的最大时间,如果2MSL后还未收到服务器重传的FIN包,就说明服务器已经收到了ACK包。

一枚热爱技术和生活的老贝比,专注于Java领域,关注【南秋同学】带你一起学习成长~

标签: #tcpip协议java