冲冲冲---TCP/IP详解
三、TCP/IP
在互联网所使用的各种协议中, 最重要的 和最著名的就是TCP和IP两个协议。 现在人们经常提到的TCP/IP并不一定是单指TCP和IP这两个具体的协议,而往往是表示互联网所使用的整个TCP/IP协议簇
1、TCP/IP参考模型:
数据链路层和物理层可以合并为网络接口层
举例:
链接:https://baike.baidu.com/item/TCP%2FIP%E5%8D%8F%E8%AE%AE/212915?fromtitle=tcp%2Fip&fromid=214077&fr=aladdin
2、数据的封装与解封装
<应用层> ----为应用进程提供服务,不同种类的应用程序会根据需要选择相应的协议(HTTP,SMTP,telnet...)
此时,A给B发送消息"hello".应用层将这个消息处理成一个数据包
<传输层>----提供两台主机之间的数据传输,传送应用层报文.
应用层将消息封装成数据包后传递到传输层,传输层会对数据包进行进一步封装,为数据包添加一个TCP/UDP头部(具体用哪个取决于软件选择什么协议), 其中含有源端口和目标端口,假如我们用IE浏览器访问一个http开头的网页时,实际上在访问对方的80端口,这个过程中系统会为IE随机生成一个端口号,假如是1000, 当数据到达传输层,包头中的源端口就是1000,目标端口就是80
<网络层>----负责相邻主机之间的通信,会把接收到的数据报封装成分组或包继续传送
传输层虽然提供了端口号,但是一个网络里有很多主机,数据包要依靠网络层来把数据传输到我们指定的主机上去.
网络层的重要协议--IP协议,当数据包到达网络层, 会给数据包添加一个IP包头,包含源目IP, 把数据传输到指定主机就是通过目标IP实现的
<数据链路层(网络接口层)>----在不可靠的物理线路上进行数据的可靠传递
数据包到达数据链路层,会给数据包加上一份二层头部(MAC子层)和二层尾部(FCS),封装后的数据包成为数据帧,帧被转换为比特,通过网络介质传输
MAC头部: 包含源目MAC地址,每台主机的MAC地址是唯一的
FCS尾部:上三层加上帧头之后,对中间的信息数据会使用一个循环校验算法,最终得到一个固定的值,我们可以利用这个值和FCS得出这个数据包的内容是否缺失
3、TCP/IP的工作:
TCP/IP意味着TCP和IP一起工作
TCP负责应用软件和网络之间的通信(比如浏览器)
IP负责计算机之间的通信
TCP负责将数据分割并装入IP包,然后在它们到达的时候重新组合它们
IP负责将包发送至接收者
4、TCP报文格式:
序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编了号,第一个字节的编号是本地随机产生的,给字节编号后,就给每一个报文段编号,seq就是这个报文段中第一个字节的数据编号
确认号ack:占4个字节,期待收到对方下一个报文段中的第一个字节的序号,序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号
确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效
同步SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。
终止FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接
PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号
5、TCP三次握手:
-
ACK:用于对收到的数据进行确认,所确认的数据由确认序列号表示。
SYN:用作建立连接时的同步信号
FIN:表示后面没有数据需要发送,通常意昧着所建立的连接需要关闭了
- 需要注意的是, 上图中出现的 ACK = x +1 的写法很容易让人误以为数据包中的 ACK 域的数据值被填成了 y+1 。 ACK = x+1 的实际含义是:
- TCP 包的 ACK 标志位(1 bit) 被置成了 1
- TCP 包的确认号(acknowledgement number ) 的值为 x+1
- 三次握手---->建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务器一共发送三个包来确认连接成功
<第一次握手> 你向妹子要微信
A主动去连接B,此时B是被动打开的,A会将SYN置为1,随机产生一个seq为x,发送给B。然后A会进入SYN_SENT状态,等待B确认
<第二次握手> 妹子同意,告诉你微信号
B收到数据包后,发现SYN=1就知道A要请求连接,然后B就会将SYN置为1,再加一个ACK,也置为1,表示B收到了A的请求并确认,同时也向A请求连接。再给自己随机生成一个初始序列号seq=y,ack=x+1,最后将数据包发送给A,并进入SYN_RCVD状态。
<第三次握手> 你加上妹子微信
A收到数据包后,检查ack是不是x+1,ACK是否为1,如果正确,会将ACK置为1,ack=y+1,将数据包发送给B,B检查完ACK和ack之后,如果正确,则连接建立成功,双方都进入ESTABLISHED状态,完成三次握手,然后他们之间就可以传递数据了
6、TCP四次挥手:
- 由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到另一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭
<第一次挥手> 情侣分手,你跟妹子说,你把我删了吧
A发起一个断开请求,FIN=1,序列号seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),用来关闭AB之间的数据传送,然后A进入FIN-WAIT-1状态。TCP规定,FIN报文即使不携带数据,也要消耗一个序号
<第二次挥手> 妹子说,好
B收到了A的断开请求,并同意对方的断开请求,就会向对方发出确认报文,ACK=1,ack=u+1,带上自己的序列号seq=v,此时,B就进入了CLOSE-WAIT状态。TCP服务器通知高层的应用进程,A向B的方向就释放了,这时候处于半关闭状态,即A已经没有数据要发送了,但是B若发送数据,A依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间
A收到了B的确认报文,此时,A就进入了FIN-WAIT-2Z状态,等待B发送连接释放报文(在收到此释放报文之前,还得接受B发来的数据)
<第三次挥手> 妹子说,那我删了
B将最后的数据发送完以后,就会向A发送连接释放(断开)报文,FIN=1,ACK=1,ack=u+1,由于在半关闭状态,B可能又发送了一些数据,假设此时的序列号为seq=w,此时,B就进入了TIME-WAIT状态,等待A的确认。
<第四次挥手> 你含泪说,好
A收到B的连接释放报文后,必须发出确认报文,ACK=1,ACK=w+1,自己的序列号是seq=u+1,此时,客户端进入了TIME-WAIT状态。
注意:此时TCP连接还没有断开,必须要经过2MSL(最大报文段生存时间)时间后,当客户端确认服务端收到确认报文时,才会进入CLOSE状态。很明显,B断开连接比A要早一点。
问题1:为什么链接的时候是三次握手,而断开需要四次?
因为当B收到A的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当B收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉A,"你发的FIN报文我收到了"。只有等到B所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次握手。
SOCKET:套接字,就是在不同主机上的应用进程之间进行双向通信的端点,比如A和B。套接字=ip地址:端口号
问题2:为什么在TIME-WAIT状态下要经过2MSL(最大报文段生存时间)时间才能进入CLOSE状态?
按道理,四个报文都发送完了就可以断开连接了,但是假设网络是不可靠的,A发送的最后一个ACK有可能会丢失,丢失了就要重发,TIME-WAIT状态就是用来重发可能丢失的ACK,那么怎么知道有没有丢失呢?在A发出最后一个ACK后,服务器如果没有收到,就会重复发送FIN片段。所以A不会立即关闭,他会设置一个计时器,等待2MSL的时间,如果在这个时间内还会收到对方发来的FIN,那么客户端就会重新发送一遍ACK并且再等待2MSL的时间(2倍的MSL),在这个时间内,没有再收到B的FIN,客户端就知道了对方已经收到ACK了,就会断开连接。当B收到ACK后,会先断开连接。
MSL:最大报文段生存时间
Windows:MSL = 2 min
linux(Ubuntu,CentOS) :MSL = 60s
UNIX :MSL = 30s
原文链接:https://blog.csdn.net/weixin_44198965/article/details/90083126