目录
- TCP协议
-
- TCP协议的面向连接
- TCP协议的可靠性
-
- [1.TCP状态转移------TIME_WAIT 状态](#1.TCP状态转移——TIME_WAIT 状态)
-
- [TIME_WAIT 状态存在的意义:](#TIME_WAIT 状态存在的意义:)
- 2.应答确认、超时重传
- 3.去重
- 4.乱序重排
- 5.滑动窗口
- TCP协议的流式服务,粘包
- UDP协议
TCP协议
TCP协议:面向连接 可靠的 流式服务
TCP协议的面向连接
使用TCP协议通信的双方必须先建立连接,具体是通过TCP的报文进行三次握手建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,从而来管理连接的状态和连接上数据的传输。TCP连接是全双工的,双方的数据可以通过一个连接进行读写。完成数据交换之后,通信双方都必须断开连接以释放系统资源,具体是通过四次挥手来断开连接。
1.三次握手
三次握手发生在客户端执行connect()的时候,该方法返回成功,则说明三次握手已经建立。三次握手示例图如下:
2.四次挥手
四次挥手发生在客户端或服务端执行close()关闭连接的时候,示例图如下:
TCP协议的可靠性
1.TCP状态转移------TIME_WAIT 状态
建立连接(三次握手)和断开连接(四次挥手)时会引起TCP状态发生变化。
TCP连接的任意一端在任一时刻都处于某种状态,当前状态可以通过netstat命令查看,下图是TCP连接从建立到关闭整个过程中通信两端状态的变化。其中CLOSED是假想的起始点,并不是一个实际的状态。
TIME_WAIT状态一般情况下是主动关闭的一端才会出现的状态。。该状态出现
后,会维持2分钟的时间,才能完全关闭。
TIME_WAIT 状态存在的意义:
(1)可靠的终止TCP连接。
挥手一共是4次,如果最后一次挥手发送的ACK确认消息丢了,这时对方没有收到确认ACK确认消息,就会重发FIN,然后收到FIN之后再给对方回复ACK。如果服务器端先关闭,服务器端如果没有TIME_WAIT 状态,第三次挥手客户端发送给服务器端的FIN会让服务器端觉得莫名其妙,因为此时服务器端已经关闭了,就无法正常完成四次挥手了。TIME_WAIT 状态就会让先关闭的一端(假设是服务器端)等待2分钟,如果这两分钟内对方不再重发FIN,说明对方已经收到ACK确认消息,这时服务器端才可以关闭。
(2)让迟来的TCP报文有足够的时间被识别并被丢弃。
假设服务器是主动关闭的一端,当服务器端处于TIME_WAIT 状态时,端口号还没有被释放出来,此时的服务器端不可以马上重新启动,在Linux 系统上,一个TCP端口不能被同时打开多次(两次及以上)。当一个TCP连接处于TIME_WAIT状态时,我们将无法立即使用该连接占用着的端口来建立一个新连接,只能等2分钟后将端口释放之后才可以重新启动服务器端,这是为了让迟来的TCP报文有足够的时间被识别并被丢弃,也就是说当某一个数据包还在路上的时候服务器端和客户端的连接断开了,然后重新启动了一个服务器端,此时这个重新启动的服务器端就会收到发给上一个服务器的数据包,这样会造成困惑,我们并不希望这样的现象出现,所以需要等待2分钟,让新服务器在这两分钟内启动不了,让网络中延迟的那个数据包先到达,发现此时端口无法收数据,然后把这个数据包丢弃,这样两分钟以后重新启动的服务器端就不会收到发给上一个服务器端的数据。
2.应答确认、超时重传
TCP协议在传输层,当把数据交到网络层之后,网络层通过IP协议进行信息的传送,无论在传输层用的是TCP协议还是UDP协议,把消息交给网络层之后都是通过IP协议进行传输的,IP是无状态无连接的,尽最大可能去提供传输,如果所传输的信息丢了,那也没办法,也就是说无论是TCP还是UDP在网络层达成IP分组之后都有可能会丢掉信息。对于UDP来说丢了就丢了,而对于TCP来说,如果信息丢了,等一段时间没有等到确认的消息,这时就需要重发这个信息,所以TCP协议的开销要比UDP大,所以TCP的可靠性是以牺牲一定的开销为代价的。TCP协议具有应答确认、超时重传的机制。
3.去重
也不用担心发过去的确认信息丢了之后对方会多收一次相同的报文,因为TCP协议具有去重的功能。
4.乱序重排
当发送的数据中途到达的次序和发送的顺序不一样也没关系,因为TCP协议具有乱序重排的功能。
5.滑动窗口
TCP还有一个功能就是滑动窗口,来进行流量控制,窗口越大单位时间内允许发送的数据就越多,窗口越小,单位时间内允许发送的数据就越少,不会让发送数据的速度太快也不会太慢。
TCP协议的流式服务,粘包
TCP 流式服务的特点,发送端执行的写操作次数和接收端执行的读操作次数之间没有任何数量关系,应用程序对数据的发送和接收是没有边界限制的。
1.粘包的产生
send发送的次数和recv接收的次数不一定就是一样的,如上图,三次send的数据有可能一次recv就收到了。由于多次连续send发送数据被对方一次收到就会产生粘包。
2.粘包的影响
粘包在不同情况下的影响不同,比如是下载文件,则没有影响,发送的多个文件可以一次性收完,但是一些交互情况是有影响的,比如客户端发送一个长方体的长、宽、高,服务器端接收这个长方体的长、宽、高之后再给客户端发送这个长方体的体积,客户端发送长方体的长、宽、高分别是20、10、2,服务器端在接收的时候由于粘包,就会一次性接收20、10、2为20102误以为20102是长方体的长,会一直等待接收长方体的宽和高,客户端也会一直等待接收服务器给它发送长方体的体积,发生了阻塞,这时粘包就产生了不好的影响。
3.解决粘包的方法
(1)让某一个端在接收数据时可以区分出数据是几个不同的报文,可以将数据用中括号"[]"括起来,这样在接收数据的时候,可以自行判断所接收的数据。
(2)可以在报文前面设计一个大小,就是用来说明一个报文到底有多大,这样的话在recv的时候接收的时候就会告诉后面有几个字节,就把那些字节全部都接收完就可以了,接收完之后,后面开始的就是一个新的报文。
(3)不要连续send,而是send发送一个数据之后就recv接收这个数据。
UDP协议
UDP协议:无连接 不可靠 数据报
UDP协议数据报服务特点
发送端应用程序每执行一次写操作,UDP模块就将其封装成一个UDP数据报发送。接收端必须及时针对每一个UDP数据报执行读操作,否则就会丢包。并且,如果用户没有指定足够的应用程序缓冲区来读取UDP数据,则UDP数据将被截断。