网络编程:深入理解TCP与UDP

网络编程:深入理解TCP与UDP_第1张图片

这是张富涛的第11篇原创

网络编程:深入理解TCP与UDP

1.概述

在网络编程这篇章中,我们简单介绍了TCP与UDP,包括他们的实现方式,以及C/S方式的代码简单实现及优化,我们已经对TCP与UDP有了一定程度上的理解,那么下面我们稍微深入一下TCP与UDP,将他们更加清晰的进行对比一下。

首先我们回顾一下TCP与UDP之间的优缺点对比:

  • TCP:优点较为安全,缺点是较慢。
  • UDP:优点较快,缺点是“丢包”。

以上是较直观的结论。那么可能大家都没注意到的一个问题来了:为什么UDP传输较快,TCP传输较慢呢?

请大家先自行思考一下,如果突然有人这样询问的时候你该怎么回答呢?

2. 问题一:为什么UDP传输较快,TCP传输较慢

首先我们回顾下“TCP”的传递消息方式,TCP需要建立一个连接,当连接建立成功之后,我们开始发送数据。而UDP是不需要建立连接的,它可以直接发送数据而不管接收消息的一方是否存在,是否能接收到,这个过程就已经比TCP快了,当然这并不是关键要素,这是其一。

其二:TCP方式传递数据时,需要保持可靠连接,就如同打电话一样,发送的一方说了一句话,对面没有听清,这时遵守消息重发机制对消息进行重新发送。而UDP不需要确认,只需要发送出数据包就好了。所以对于TCP来说,数据的“发送——确认”这个循环是十分耗时的,这才是关键点。

其三:TCP是在一个可靠连接下遵守一问一答的形式发送接收数据,一次只能发一条数据,而UDP呢,UDP是属于数据包的形式发送,调用DatagramSocket.send()方法,底层会将一个大包拆分成多个小包,一次性发送多个数据包,所以UDP比TCP快的多了。

以上就是UDP协议方式为什么比TCP更快的原因了,已经快把UDP吹上天去了,那么我们来看下一个问题吧!

3. 问题二:UDP协议为什么丢包

  • 接收方不存在或处理时间过长:UDP发送时不会管接收方的状态,这种不负责的发送方式,如果接收方不存在或接收方正在处理上一个数据包无暇接收和处理现在发送的包,就会造成丢包的情况。

  • 发送数据包过大:虽然DatagramSocket.send()方法会帮你做大包切割成小包发送的事情,但包太大也不行。例如超过50K的一个udp包,不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send。

  • 发送的包较大,超过接受者缓存导致丢包:我们刚刚介绍完UDP接收包的代码实现方式:在接收一个包之前,我们需要先创建一个缓冲数组,用来预估接收数据包的大小(不能小于预估长度),虽然不可小于此长度,但太超于此长度也会导致超出缓存让我们接收不全,这种情况可以设置socket接收缓冲。

  • 发送的包频率太快:虽然每个包的大小都小于mtu size 但是频率太快,例如40多个mut size的包连续发送中间不sleep,也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决,但有时解决不了。所以在发送频率过快的时候还是考虑sleep一下吧。

主要UDP丢包的方式就是这些,虽然UDP会有丢包的风险,可是它胜在通讯成本低,速度快,所以也成为主流即时通讯所用的一种协议。

QQ客户端之间的消息传送也采用了UDP模式,因为国内的网络环境非常复杂,而且很多用户采用的方式是通过代理服务器共享一条线路上网的方式,在这些复杂的情况下,客户端之间能彼此建立起来TCP连接的概率较小,严重影响传送信息的效率。而UDP包能够穿透大部分的代理服务器,因此QQ选择了UDP作为客户之间的主要通信协议。

大家都知道,UDP 协议是不可靠协议,它只管发送,不管对方是否收到的,但它的传输很高效。但是,作为聊天软件,怎么可以采用这样的不可靠方式来传输消息呢?于是,腾讯采用了上层协议来保证可靠传输:如果客户端使用UDP协议发出消息后,服务器收到该包,需要使用UDP协议发回一个应答包。如此来保证消息可以无遗漏传输。之所以会发生在客户端明明看到“消息发送失败”但对方又收到了这个消息的情况,就是因为客户端发出的消息服务器已经收到并转发成功,但客户端由于网络原因没有收到服务器的应答包引起的。

4. 问题三:为什么TCP协议方式较为安全

TCP协议方式相较于UDP方式更为安全可靠,是一种“面向连接”的通讯方式。那么它除了三次握手之外依然有其他的机制会保证通讯更加可靠。下面包括三次握手,我们简单的一一介绍:

  • 建立连接前需要进行三次握手:简单来说,三次握手可以理解为A问:“你收到我的发送的信息了吗?”B答:“我收到了,那你收到我这条信息了吗?” A答:“我收到了!” 这样的三次通讯才能进行连接。(这里只是简单介绍三次握手,真正的实现方式大家可自行百度)
  • TCP发送时先将数据被分割成TCP认为最适合发送的数据块。
  • 当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。(类似打电话,对方听不清重说一次)
  • 当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒 。
  • TCP接收到数据之后会进行校验,校验出错则丢弃报文段,不给出响应,客户端发送消息超时没有获得回执时会重发数据。
  • TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
  • IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。
  • TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

5. 问题四:TCP连接有什么缺点吗?

TCP的作为一种年代久远的通讯方式目前有着很多缺点,本文只从浅显的地方指出一点:

对于这个问题我们想到的就是慢,成本高,对于TCP连接前需要三次握手来说,目前业界提出了“TCP Fast Open (TFO)”扩展机制,两次握手之后就可以发送正常业务数据了。但这需要客户端和服务器端内核层面都支持才行: Linux内核3.6客户端,3.7支持服务器端。而TCP关闭连接也需要“四次挥手”,需要产生四次交互,这在移动互联网环境下,显得有些多余。快速关闭,快速响应,冗余交互导致网络带宽被占用。



---------------

公众号:张富涛的学习笔记(ID:futaoNT)

知乎:张富涛

CSDN:张富涛

这是一个在夜晚可以靠编程拯救世界的程序员,关注他将在第一时间获悉他的知识、工作心得!

长按下图二维码关注:
网络编程:深入理解TCP与UDP_第2张图片

你可能感兴趣的:(网络编程,网络,java,tcpip,udp)