TCP 和 UDP 的区别

OSI 和 TCP/IP 模型在传输层定义两种传输协议:TCP(或传输控制协议)和 UDP(或用户数据报协议)。UDP 与 TCP 的主要区别在于 UDP 不一定提供可靠的数据传输。也就是说,在收发数据前,一个TCP连接必须要经过三次“对话”和对方建立可靠的连接。

类型

TCP

UDP

是否连接

面向连接

面向非连接

传输可靠性

可靠的

不可靠的

应用场合

传输大量的数据

少量数据

速度

TCP

TCP 连接的建立和断开

三次握手过程

  1. 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三次握手的一部分。客户端把这段连接的序号设定为随机数 A。
  2. 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK 的确认码应为 A+1,SYN/ACK 包本身又有一个随机序号 B。
  3. 最后,客户端再发送一个ACK。当服务端受到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包序号被设定为收到的确认号 A+1,而响应则为 B+1。

四次挥手过程

注意: 中断连接端可以是客户端,也可以是服务器端. 下面仅以客户端断开连接举例, 反之亦然.

  1. 客户端发送一个数据分段, 其中的 FIN 标记设置为1. 客户端进入 FIN-WAIT 状态. 该状态下客户端只接收数据, 不再发送数据.
  2. 服务器接收到带有 FIN = 1 的数据分段, 发送带有 ACK = 1 的剩余数据分段, 确认收到客户端发来的 FIN 信息.
  3. 服务器等到所有数据传输结束, 向客户端发送一个带有 FIN = 1 的数据分段, 并进入 CLOSE-WAIT 状态, 等待客户端发来带有 ACK = 1 的确认报文.
  4. 客户端收到服务器发来带有 FIN = 1 的报文, 返回 ACK = 1 的报文确认, 为了防止服务器端未收到需要重发, 进入 TIME-WAIT 状态. 服务器接收到报文后关闭连接. 客户端等待 2MSL 后未收到回复, 则认为服务器成功关闭, 客户端关闭连接.

TCP 的状态转换

  • CLOSED:套接字的初始状态,表示TCP连接是新建“未打开的”状态或者已经“关闭着的”。
  • LISTEN :服务端仅有的状态,表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接。
  • SYN_RCVD :表示服务器接收到了来自客户端请求连接的SYN报文。这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂。
  • SYN_SENT :SYN_SENT 状态表示客户端已发送SYN报文,当客户端SOCKET 执行 connect() 进行连接时,它首先发送 SYN 报文,然后随即进入到 SYN_SENT 状态,并等待服务端的发送三次握手中的第2个报文。
  • ESTABLISHED :表示 TCP 连接已经成功建立。
  • FIN_WAIT_1 :FIN_WAIT_1 状态是当 SOCKET 在 ESTABLISHED 状态时,它想主动关闭连接,向对方发送了 FIN 报文,此时该 SOCKET 进入到 FIN_WAIT_1 状态。
  • FIN_WAIT_2 :FIN_WAIT_2 状态下的 SOCKET 表示半连接,即有一方调用 close() 主动要求关闭连接。注意:FIN_WAIT_2 是没有超时的(不像TIME_WAIT 状态),这种状态下如果对方不关闭(不配合完成4次挥手过程),那这个 FIN_WAIT_2 状态将一直保持到系统重启,越来越多的 FIN_WAIT_2 状态会导致内核 crash。
  • TIME_WAIT :表示收到了对方的 FIN 报文,并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在Internet上的最长生存时间。)。
  • CLOSING :这种状态在实际情况中应该很少见。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是 CLOSING 状态表示一方发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却也收到了对方的 FIN 报文。当双方几乎在同时 close() 一个 SOCKET 的话,就出现了双方同时发送 FIN 报文的情况,这是就会出现 CLOSING 状态,表示双方都正在关闭 SOCKET 连接。
  • CLOSE_WAIT :表示正在等待关闭。当对方 close() 一个 SOCKET 后发送 FIN 报文给自己,你的系统毫无疑问地将会回应一个 ACK 报文给对方,此时 TCP 连接则进入到 CLOSE_WAIT 状态。接下来需要检查自己是否还有数据要发送给对方,如果没有的话也就可以 close() 这个 SOCKET 并发送 FIN 报文给对方,即关闭自己到对方这个方向的连接。有数据的话则看程序的策略,继续发送或丢弃。简单地说,当处于CLOSE_WAIT 状态下,需要完成的事情是等待去关闭连接。
  • LAST_ACK :当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态。当收到对方的ACK报文后,也就可以进入到 CLOSED 可用状态了。

流程图

服务器连接数量突增的可能原因

服务器保持了大量TIME_WAIT状态

这种情况比较常见,一些爬虫服务器或者WEB服务器(如果网管在安装的时候没有做内核参数优化的话)上经常会遇到这个问题,这个问题是怎么产生的呢?

TIME_WAIT是主动关闭连接的一方保持的状态,对于爬虫服务器来说他本身就是“客户端”,在完成一个爬取任务之后,他就 会发起主动关闭连接,从而进入TIME_WAIT的状态,然后在保持这个状态2MSL(max segment lifetime)时间之后,彻底关闭回收资源。为什么要这么做?明明就已经主动关闭连接了为啥还要保持资源一段时间呢?这个是TCP/IP的设计者规定 的,主要出于以下两个方面的考虑:

  1. 防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)
  2. 可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。

解决思路很简单,就是让服务器能够快速回收和重用那些TIME_WAIT的资源。

服务器保持了大量CLOSE_WAIT状态

如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直 被程序占着。个人觉得这种情况,通过服务器内核参数也没办法解决,服务器对于程序抢占的资源没有主动回收的权利,除非终止程序运行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值