TCP协议

一、概念

TCP 是传输层的协议,全称是叫做 Transmission Control Protocol。

在这里插入图片描述
应用层:
传输层:
网络层:
接口层:

二、TCP 协议

TCP 是整个 TCP/IP 协议族中最重要的传输层协议,它定义了一种面向连接的、可靠的、基于流的传输方式。
HTTP 是基于 TCP 的,所以说 TCP 是整个互联网的协议其一并不为过。
同时,我们在使用 HTTP 协议实现应用系统间的交互时,也经常免不了会与 TCP 打上交道。因此有必要了解一些基本机制。

TCP 的特点?

  • 首先,TCP 是基于连接的,也就是在进行数据传输之前,客户端与服务端(或者说是通信的双方)需要先建立一个可信的连接。
    在数据传输结束后,再通过一种协定的方式断开连接,由通信的双方释放资源。这里涉及到的,就是常说的"三次握手"、“四次挥手”

  • 其次,TCP 是可靠的,它定义了一种数据包的"超时重传机制",简单说,就是每一个数据包在发送出去后的都会等待一个响应。
    如果指定时间内没有收到响应,由发送方进行一定次数的重传来保证数据的可靠传输。

  • 最后,TCP 是基于流的,这是指在传输数据时应用层不需要关注数据包的边界,TCP在数据传输时会自动根据网络环境将数据进行缓冲、分组、合并。
    这点跟基于报文的协议(UDP)是截然不同的。当然,基于流的传输也保证了数据收发的有序性,因此每个数据包都附带上一个属于当前连接的序列号。

怎么理解全双工?
全双工是通讯上的术语,一般在软件开发领域提到的并不多。
这是指数据同时在两个方向上传输,TCP 是基于全双工的可信传输协议。
当然 UDP 也可以实现全双工的传输,但 TCP 只能实现点对点的传输,无法支持广播或者多播(分组)
黑板:半双工的区别在于,同一时间只能有一个方向的传输

三、TCP 工作流程

一个TCP 正常的通讯流程,会包含建链(建立连接)、传输数据、拆链(关闭连接),
在这里插入图片描述
据上图所示,在进行 TCP 进行数据传输时,都不可避免的会经过这两个阶段:

三次握手建立连接

执行数据传输、双方读写

四次挥手释放连接

四、 三次握手

在这里插入图片描述

在建立TCP连接时,需要经过三次交互,也成为三次握手(HandShake)。

1、客户端发起连接请求,发送 SYN包(SYN=i)到服务器,并进入到SYN-SEND状态,等待服务器确认
2、服务器收到SYN包后,必须确认客户的 SYN(ack=i+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器进入SYN-RECV状态
3、客户端收到服务器的SYN+ACK包,向服务器发送确认报ACK(ack=k+1),此后客户端和服务器进入ESTABLISHED状态,双方可以开始传送数据。

在谈论三次握手的时候,有几个问题是需要关注的:

问题1. 为什么是三次握手

这个问题在技术面试时屡试不爽,原话是能不能两次,或者是四次握手呢?
答案就是,TCP 是可靠的传输,在建立连接时就应该经过两端的确认过程,如上面的流程,只有在三次握手的情况下,客户端和服务端都经过了一次真正(SYN+ACK)的确认过程。这样的连接便认为是可信的。
此外,如果仅仅只是两次握手,一旦网络不稳定造成 SYN 包重传则会直接导致重复建立连接,浪费资源。

问题2. 什么是syn flood攻击

syn flood 是一种经典的 ddos攻击手段,这里面用到了TCP 三次握手存在的漏洞。
在上面的图中,可以看到当服务端接收到 SYN 后进入 SYN-RECV 状态,此时的连接称为半连接,同时会被服务端写入一个 半连接队列。
想象一下,如果攻击者在短时间内不断的向服务端发送大量的 SYN 包而不响应,那么服务器的半连接队列很快会被写满,从而导致无法工作。
实现 syn flood 的手段,可以通过伪造源 IP 的方式,这样服务器的响应就永远到达不了客户端(握手无法完成);
当然,通过设定客户端防火墙规则也可以达到同样的目的。

对 syn flood 实现拦截是比较困难的,可以通过启用 syn_cookies 的方式实现缓解,但这通常不是最佳方案。
最好的办法是通过专业的防火墙来解决,基本上所有的云计算大T 都具备这个能力。
关于 syn flood 可以看看这篇文章

问题3. 半连接队列和全连接队列如何调优

这里提到了一个"半连接队列"(syns queue),与其对应的还有一个 “全连接队列”(accept queue)
前者用于暂存未建立完全的连接,后者是连接在成功建立后进入的一个队列。
半连接队列默认大小可以通过内核参数调整:

echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog

黑板:tcpmaxsynbacklog 在 syncookies 开启时是无效的,这两个选项存在冲突

对于全连接队列,如果服务器未能及时通过 accept 调用将其中的连接取走,会导致队列溢出(连接失效)

全连接队列的大小的内核调优方式:

echo 4096 > /proc/sys/net/core/somaxconn

那么,是不是只有内核调优这种方法能影响这两个参数呢?答案是否定的。
实际上,在应用层调用 socket listen 时也支持设置一个 backlog参数,这几个之间的关系如下:

半连接队列长度 = min(backlog,内核 net.core.somaxconn,内核tcp_max_syn_backlog)

全连接队列长度 = min(backlog,内核 net.core.somaxconn)

黑板:一般的应用服务器如 netty、tomcat 都支持设置 backlog 参数,但是在真正进行调优时还需要配合考虑内核参数的配置。

五、 四次挥手

在这里插入图片描述

在释放连接时,由于TCP是全双工的,因此最后要由两端分别进行关闭,这个流程如下:

1、客户端发送一个FIN,用来关闭客户端到服务器的数据传送,客户端进入FINWAIT1状态。
2、服务器收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务器进入CLOSEWAIT状态,而客户端进入FINWAIT2状态。
3、服务器发送一个FIN,用来关闭服务器到客户端的数据传送,服务器进入LASTACK状态。
4、客户端收到FIN后,客户端进入TIMEWAIT状态,接着发送一个ACK给服务器,确认序号为收到序号+1,服务器进入CLOSED状态,完成释放。

关闭连接有主动关闭和被动关闭一说,这里为了简化理解,我们以客户端作为主动关闭方,服务器为被动关闭方。

四次挥手需要关注的问题:

问题1. 为什么是四次挥手

发送FIN的一方就是主动关闭(客户端),而另一方则为被动关闭(服务器)。
当一方发送了FIN,则表示在这一方不再会有数据的发送。
其中当被动关闭方受到对方的FIN时,此时往往可能还有数据需要发送过去,因此无法立即发送FIN(也就是无法将FIN与ACK合并发送),
而是在等待自己的数据发送完毕后再单独发送FIN,因此整个过程需要四次交互。

问题2. 什么是半关闭

客户端在收到第一个FIN的ACK响应后,会进入FINWAIT2 状态时,此时服务器处于 CLOSEWAIT状态,这种状态就称之为半关闭。
从半关闭到全关闭,需要等待第二次FIN的确认才算结束。此时,客户端要等到服务器的FIN才能进入TIMEWAIT,如果对方迟迟不发送FIN呢,则会等待一段时间后超时,这个可以通过内核参数tcpfin_timeout控制,默认是60s。

问题3. 为什么服务器会有大量 closewait

半关闭的状态下的服务器连接会处于 closewait 状态,直到服务器发送了FIN。
那么在应用层则是调用socket.close()会执行FIN的发送,如果服务器出现大量CLOSE_WAIT状态的连接,那么有可能的原因:

  • 服务器压力过大,根本来不及调用close
  • 存在连接泄露问题(Bug),服务器未及时关闭连接

问题4. timewait 会带来什么问题

当客户端收到了对方的FIN时,会进入TIMEWAIT状态,此时会保持一段时间再进入CLOSE状态。
这么做的原因主要还是为了可靠的关闭连接。在将TCP 进行可靠性设计之时就考虑了许多网络的不稳定性的因素,比如:
发送给对方的ACK 可能会无法及时收到,此时对方可能重传FIN过来,如果提前进入CLOSE则会返回RST而不是ACK,就会影响关闭流程。

因此 TIMEWAIT 状态默认会持续一段时间,直到确认不会再有重传的数据包之后再安全的关闭。

黑板:这里timewait的持续时间默认是 2*MSL(总共1分钟),这个MSL叫Max Segment Lifetime,也就是关于一个数据包在网络中传输的最大生命周期的预设。 MSL默认是30s,当然这个值在现在已经可以大幅度缩减。可见在当时在设计之初,网络状况有多么的糟糕。

那么timewait会带来什么问题?
如果频繁的主动关闭连接,可能会产生大量 timewait,由于timewait 的连接占用了一个句柄及少量内存(4K),那么就有可能会影响其他连接的建立,比如:

出现 too many open files 异常…

该如何解决:

重用连接,避免频繁关闭,比如使用连接池

参数调优,比如开启tcptwreuse选项支持timewait连接的重复使用。

黑板:HTTP 协议里头发现了timewait的问题,于是在 HTTP 1.1 中定义了 KeepAlive 用来支持连接的重用。

问题5. RST 是什么,为什么会出现

RST 是一个特殊的标记,用来表示当前应该立即终止连接。以下这些情况都会产生RST:

  • 向一个未被监听的端口发送数据
  • 对方已经调用 close 关闭连接
  • 存在一些数据未处理(接收缓冲区),请求关闭连接时,会发送RST强制关闭
  • 某些请求发生了超时
期末大作业基于python的足球运动员数据分析源码+数据集(高分项目),个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的学生和需要项目实战练习的学习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,如果有需要的话可以放心下载使用。 期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于pyth
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值