首先它们有一个共同点就是都是传输层的协议;
然后我将从协议字段、连接管理、可靠性和数据发送方式四方面说一下它们的区别:
一、从协议字段来说
UDP协议报头如下:
其中
16位源端口号表示发送方的端口号
16位目的端口号表示接收方的端口号
16位UDP长度表示整个数据报(UDP首部+UDP数据)的最大长度
16位校验和就是校验接收的数据和发送的数据是否一致,如果校验和出错,则直接丢弃此次数据
所以UDP的报头是定长的,占8个字节
TCP协议报头如下:
其中
16位源端口号表示发送方的端口号
16位目的端口号表示接收方的端口号
32位序号表示发送方发送批量字节时第一个字节数据的序号(第一次发送的时候序号会由本地随机产生),序号通常用syn表示
32位确认序号表示对发送方发送的批量数据的确认,告诉发送方下一次从哪个字节开始发送,并默认表示该字节之前的数据已经全部接收到,通常用ack表示
4位首部长度表示TCP报头有多少个四字节,由于4位比特位最大能表示15,所以TCP报头最长就是60个字节
6位保留位都为0,用于以后定义新的用途
6位标志位:
URG:紧急指针,置1时有效,表示此数据需要被紧急处理
ACK:置1时表示确认序号有效,置0时确认序号无效
PSH:置1时表示告诉接收方应用程序立即将数据从接收缓冲区读走
RST:复位标志,表示对方要求重置连接
SYN:请求建立连接,SYN为1,ACK为0表示请求建立连接;SYN为1,ACK为1表示对方收到了你的请求,并同意建立连接
FIN:释放连接,置1时表示此报文的发送方的数据已经全部发送完毕,要求断开连接
16位窗口大小表示发送方缓冲区剩余空间的大小,即无需等待确认应答而可以继续发送数据的最大值
16位校验和表示校验接收的数据和发送的数据是否一致,如果校验不通过,则认为数据有问题
16位紧急指针用来标识哪部分数据是紧急数据
选项占40个字节。
所以TCP的报头标准长度是20个字节,最大60个字节。
二、从连接管理来说
UDP无连接,TCP是面向连接的
UDP无连接的意思是,发送数据前不需要建立连接,只需要知道对端的地址信息【IP和端口号】就可以直接进行数据传输
TCP面向连接的意思是,发送数据前一定要先建立连接,而建立连接主要是通过三次握手实现的;最后当数据发送完毕后需要断开连接时,也需要通过四次挥手完成。
其中TCP三次握手四次挥手参见:TCP三次握手四次挥手过程
三、从可靠性来说
UDP不可靠,TCP是可靠传输
UDP不可靠的意思是,只管发送,不确定是否已安全到达对方,就算因为某些原因没有到达对方,也不会给应用层返回任何错误信息。
TCP可靠传输主要是通过确认应答机制、超时重传机制以及滑动窗口来实现的。
确认应答机制:发送方每次发送数据时都会对发送的数据进行编号【也就是序号】,当接收方收到了此次数据之后,会对其进行确认,主要是通过确认序号实现的,告诉发送方下次从哪个字节开始发送数据,默认该字节之前的数据已全部收到。而且,通过序号和确认序号也可以保证数据按序到达
超时重传机制:发送方发送了一些数据给接收方,但是由于网络拥塞等原因,此时的数据没有到达接收方,而此时发送方在一个特定时间间隔内没有收到接收方的确认应答信息,就会对此次的数据进行重发。但是也有可能是接收方发送的确认信息丢了,此时由于超时重传机制,接收方会收到很多的重复数据,那么接收方的TCP也可以利用序号识别出哪些是重复的信息并进行丢弃,这样可以达到去重的效果。
滑动窗口机制:由于对每次发送的数据段都要有一个确认应答,收到确认信息后再发送下一个数据段会降低数据传输效率。所以滑动窗口的产生就是为了在保证数据可靠到达的情况下,尽可能提高数据传输效率。这里的窗口指的就是无需等待确认应答信息而可以继续发送数据的最大值。比如说,我现在窗口大小为4000个字节,分成4个数据段发送,每个数据段大小为1000个字节,那么我就可以直接发送前四个数据段的时候而不需要等待任何ACK信息。当收到第一个ACK后,滑动窗口往后移,继续发送第五个段的数据,以此类推。
而发送方发送数据之前,为了不让由于自己发送太快太多,导致接收方接收不过来,而造成大量的超时重传这种事情发生,它会选择一个合适的窗口大小发送数据。而这里的窗口大小主要是通过流量控制和拥塞控制机制来确定的。简单来说就是,我发送数据的时候不仅要考虑对方接收数据的能力【流量控制】,还要考虑网络状况【拥塞控制】。所以最终的窗口大小是选 接收方的接收窗口和拥塞窗口 中较小的一个。
另外,为了不让由于ACK确认包的丢失造成超时重传,影响传输性能,引入了快重传机制:在双方通信中,如果接收方接收到了第二条数据,但是没有接收到第一条数据,这时会立即向发送方连续(间隔)发送三条第一条数据的重传请求;发送方收到连续三次的重传请求后会将指定数据进行重传。
但是在第三次发送重传请求之前,数据有可能刚好到达(延迟到达),这时候因为重传请求不足三次,发送方就不需要进行重传(连发三次,避免因为网络阻塞而导致数据延迟到达进行重传),接收方只有连续接收到三次重传请求时才会进行重传
四、从数据发送方式来说
UDP是面向数据报,TCP是面向字节流的
UDP面向数据报的意思就是,用户给多少数据就一次性发送多少。
TCP面向字节流的意思就是,TCP可以灵活控制数据的收送过程,如果数据太长,则会被拆分成多个TCP数据包进行发送;读取数据时也可以灵活读取。
另外,TCP还有一些提高性能的机制,比如延迟应答、捎带应答
延迟应答:接收方收到数据后并不立即回复,而是等待一段时间后(500ms)进行回复,这样可以尽可能保证窗口大小维持最大数据吞吐量
捎带应答:将确认序号放到即将要发送的数据头信息中,避免纯TCP头部的确认回复占用带宽
而且TCP在进行连接管理时,还有对应的保活机制:
TCP通信双方长时间(7200s)没有数据往来,这时候每隔一段时间(75s)向对方发送保活探测数据包(要求对方确认应答),倘若发送多次保活探测数据包(9次)都没有确认应答,这时候就认为连接断开了
UDP和TCP存在的问题:
先说UDP,由于UDP是面向数据报的,不会对数据进行任何拆分,一方面来说,由于UDP协议本身对数据长度有限制,不能超过64k-8,如果发送的数据大于64k-8,就需要用户在应用层对数据进行分包操作,否则数据就会发送识别;另一方面,数据链路层在发送数据时对数据的长度也是有要求的,这样一来,网络层的IP就得担起分片和组装的任务了;而TCP由于是面向字节流的,在发送数据前就确定了一次发送数据的最大段大小,可以保证这个数据大小不会超过链路层一次可以发送的最大数据大小,所以不用在IP层进行数据的分片和组装。
再说TCP,虽说TCP不用在IP层进行数据的分片和组装,但是在发送数据的时候,由于数据没有边界之分,会产生粘包问题,所以需要用户在应用层对每次要发送的数据做一些边界区分,比如加一些特殊字符【需要转义】、或者定长发送,或者不定长发送数据;反观UDP就不会产生粘包问题了。