Android网络编程(四)-TCP / UDP协议

一、UDP 与 TCP 简单对比
UDP

在传送数据前不需要先建立连接,远地的主机在收到UDP报文后也不需要给出任何确认。虽然UDP不提供可靠交付,但是正是因为这样,省去和很多的开销,使得它的速度比较快,比如一些对实时性要求较高的服务,就常常使用的是UDP。对应的应用层的协议主要有 DNS,TFTP,DHCP,SNMP,NFS 等。

优点: 数据传递快,比TCP稍安全。 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。但UDP也是无法避免攻击的,比如:UDP Flood攻击……

缺点: 不可靠,不稳定。因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。

TCP

提供面向连接的服务,在传送数据之前必须先建立连接,数据传送完成后要释放连接。因此TCP是一种可靠的的运输服务,但是正因为这样,不可避免的增加了许多的开销,比如确认,流量控制等。对应的应用层的协议主要有 SMTP,TELNET,HTTP,FTP 等。

优点: 连接可靠。TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。

缺点: 慢,效率低,占用系统资源高,易被攻击。 TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。 而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。

应用场景:

TCP : 当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。

UDP: 当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,这时就可以使用UDP。 比如,日常生活中,常见使用UDP协议的应用如下: QQ语音 QQ视频 TFTP ……

TCP UDP
是否连接 面向连接 面向非连接
传输可靠性 可靠 不可靠
速度
系统资源占用 较多 较少
模式 流模式 数据报模式
数据顺序 保证顺序 不保证顺序
二、TCP的三次握手与四次挥手

2.1 三次握手

最开始的时候客户端和服务器都是处于CLOSED状态,TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态。

Android网络编程(四)-TCP / UDP协议_第1张图片

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。此后双方就可以开始通信了。

简单理解:

模拟一个场景,张三李四在路上隔着100米看到了对方,但是由于大雾等原因不能100%确认,然后:

第一次握手:张三首先向李四招手(syn),等待李四给反馈
第二次握手:李四看到张三向自己招手后,向对方点头微笑并同时挥手(syn +ack),此时张三确认了李四,进入了established状态。
第三次握手:张三看到了李四挥手,向对方点头微笑。此时李四也确认了张三,也进入了established状态。

我们看到这个过程中一共是四个动作,张三招手-李四点头微笑-李四招手-张三点头微笑。其中李四连续进行了2个动作,先是点头微笑(回复对方),然后再次招手(寻求确认),实际上可以将这两个动作合一,招手的同时点头和微笑(syn+ack)。于是四个动作就简化成了三个动作,张三招手--李四点头微笑并招手--张三点头微笑。这就是三次握手的本质,中间的一次动作是两个动作的合并。

  • syn_sent: syn package has been sent
  • syn_rcvd: syn package has been received

2.2 数据传输

经过三次握手之后,Client与Server确认开始通信。

Android网络编程(四)-TCP / UDP协议_第2张图片

因为tcp链接是双工的,双方都可以主动发起数据传输。不过无论是哪方喊话,都需要收到对方的确认才能认为对方收到了自己的喊话。

还拿上面的例子:

张三喊了一句话(data),李四听见了之后要向张三回复自己听见了(ack)。

如果张三喊了一句,半天没听到李四回复,这里有两种情况:要么是张三自己的话被大风刮跑了,李四没听见;要么是李四听见了,但是李四的话被大风刮跑了,没传给张三,这两种情况都需要张三重新喊话,这就是tcp重传

既然会重传,李四就有可能同一句话听见了两次,这就是去重。重传和去重工作操作系统的网络内核模块都已经帮我们处理好了,用户层是不用关心的。

张三可能是个高射炮,一说连说了八句话,这时候李四可以不用一句一句回复,而是连续听了这八句话之后,一起向对方回复说前面你说的八句话我都听见了,这就是批量ack

但是张三也不能一次性说了太多话,李四的脑子短时间可能无法消化太多,两人之间需要有协商好的合适的发送和接受速率,这个就是TCP窗口大小

2.3 四次挥手

Android网络编程(四)-TCP / UDP协议_第3张图片

数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态。

第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。

第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手,连接关闭

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

Android网络编程(四)-TCP / UDP协议_第4张图片

依然简单用上面小例子说明:

张三向李四挥手告别(FIN)
李四向张三微笑点头(ASK), 确认可以告别了,此时张三不说话了,但是还在听,因为李四可能还有话没有说完。
李四话说完了,向张三也挥手告别(FIN)
张三微笑点头(ASK)
此时两人对话算彻底结束。

上面有一个非常特殊的状态time_wait,它是主动关闭的一方在回复完对方的挥手后进入的一个长期状态,这个状态标准的持续时间是2个MSL(4分钟),4分钟后才会进入到closed状态,释放套接字资源。不过在具体实现上这个时间是可以调整的。它的作用是重传最后一个ack报文,确保对方可以收到。因为如果对方没有收到ack的话,会重传fin报文,处于time_wait状态的套接字会立即向对方重发ack报文。同时在这段时间内,该链接在对话期间于网际路由上产生的残留报文(因为路径过于崎岖,数据报文走的时间太长,重传的报文都收到了,原始报文还在路上)传过来时,都会被立即丢弃掉。4分钟的时间足以使得这些残留报文彻底消逝。不然当新的端口被重复利用时,这些残留报文可能会干扰新的链接。

三、若干问题

1.为什么是三次握手而不是两次握手或四次握手?

两次做不到,四次太浪费,第二次握手,Server可以同时syn+ask,节省一次握手。

2.为什么连接的时候需要三次握手,而断开的时候要四次挥手?

只是对于三次握手来说中间的两个步骤是可以合并成一次的,而对于四次挥手来说则是不可以合并,因为四次挥手发送的FIN报文仅仅表示对方不再发送数据了但是还能接收数据,所以要等自己这边发出FIN之后,才能close。

3.如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

4.Server端易受到SYN攻击?

服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。

防范SYN攻击措施:降低主机的等待时间使主机尽快的释放半连接的占用,短时间受到某IP的重复SYN则丢弃后续请求。

5.三次握手过程中的第三次握手的ACK丢失会怎么办?

在第二次握手之后,服务器会等待客户发送过来的ACK,如果没有收到,那么会重新发送SYN + ACK,一般会重复几次,如果还没有收到,那么服务器会关闭这次连接,即进入CLOSED状态,但是客户会以为连接已经建立,会向服务器发送数据,这时服务器会发送RST包来告诉客户重新建立连接(从第一次握手开始)。

6.四次挥手过程中第四次挥手的ACK丢失会怎么办?

在第三次挥手中,客户对服务器的终止报文段进行确认,并发送ACK,此时客户进入TIME_WAIT状态,如果ACK丢失,服务器就会重新发送第三步的终止报文段,来使客户的计时器重置,再次发送ACK,但是,如果服务器重发的终止报文段未能在客户的计时器销毁之前到达客户,那么客户会进入CLOSED状态,服务器收不到ACK确认报文段,那么本次关闭不会成功.

7.为什么client要先进入TIME-WAIT状态,等待2MSL时间后才进入CLOSED状态?

为了保证server能收到client的确认应答。 若client发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,server等待超时后就会重新发送连接释放请求,但此时client已经关闭了,不会作出任何响应,因此server永远无法正常关闭。

参考:

https://www.linuxidc.com/Linux/2018-08/153696.htm
https://blog.csdn.net/qzcsu/article/details/72861891
https://www.cnblogs.com/williamjie/p/9390164.html

你可能感兴趣的:(Android网络编程(四)-TCP / UDP协议)