文章目录
- 1、计算机模型
- 2、客户端和服务端通信——TCP协议
- (1)socket套接字
- (2)TCP三次握手——创建socket
- (3)连接的本质
- (4)TCP四次挥手——释放socket资源
- (5)TCP的滑动窗口机制及重传机制
- (6)发送方窗口
- (7)接收方窗口
- 3、TCP常见问题
- (1)什么是半连接队列?
- (2)什么是自动重传?
- (3)ISN(Initial Sequence Number)是固定的吗?
- (4)三次握手过程中可以携带数据吗?
- (6)SYN攻击是什么?
- (7)挥手为什么需要四次?
- (8)四次挥手释放连接时,等待2MSL的意义?
- (9)TIME_WAIT状态过多有什么危害?
- (10)如何解决TIME_WAIT状态过多?
1、计算机模型
- 用户空间:应用层(会话层、表示层)
- 内核空间:传输层(TCP/UDP)、网络层、数据链路层、物理层
2、客户端和服务端通信——TCP协议
- 应用层组织好HTTP请求数据——用户空间
- 请求行:请求数据的第一行。其中GET表示请求方式, / 表示请求资源路径,HTTP/1,1表示协议版本
- 请求头:第二行开始,格式为key:value形式
- 请求体:POST请求的最后一部分,存放请求参数
- 传输层建立连接——内核空间
- TCP是面向连接的、可靠的传输层协议
- 发送数据
- 断开连接
(1)socket套接字
socket套接字是TCP/IP协议的网络通信的基本操作单元,包含了五中信息:
- 连接使用的协议
- 本地主机的IP地址
- 本地进程的协议端口
- 远程主机的IP地址
- 远程主机进程的协议端口
(2)TCP三次握手——创建socket
-
客户端发送SYN请求给服务端,SYN(i),客户端进入SYN_SEND(发送)状态等待服务器确认
-
服务端收到客户端的连接请求后,给客户端发送SYN(j)+ACK(i+1)响应,服务端进入SYN_RECEIVDE(接收)状态
-
客户端收到服务端的响应后,给服务端发送ACK(j+1)响应,客户端和服务端进入ESTABLISHED(连接)状态
所谓的HTTP长链接、短连接的本质其实是TCP的长短连接
(3)连接的本质
-
三次握手成功后,通信双方会在各自内核空间开辟一些资源。比如:发送队列和接收队列
-
客户端用户要读取服务端资源,不是直接和服务器直接对接(客户端的读取和服务端的发送时异步的)。内核收到服务器的数据后,放到接收队列里面去。然后用户再去内核的接收队列中取数据——即IO模型。
连接是通信双方内核的传输层去建立的,即socket的创建。数据的发送和接收是用户层和内核之间(socket套接字)的交互。
思考:一个本地进程可以跟一个目标进程建立多少个连接呢?
答:操作系统中端口号是16位,如果确定了本地IP和端口、以及目标IP和端口、理论上是能创建65535条,但是一般操作系统对可用端口做了限制(比如:1024~65535)。那么我可以再插一个网卡,换一个IP或者端口,就可以再创建这么多连接。这样下去,是不是就能创建越来越多的连接了?
当然不是,每一个连接都是一个文件描述符。当达到操作系统允许创建的最大描述符个数时,就会创建失败。此外,创建连接,还需要消耗cpu、内存、线程资源。所以这几项都会对创建的socket连接数做出限制。
(4)TCP四次挥手——释放socket资源
在断开连接之前客户端和服务器都处于ESTABLISHED状态,双方都可以主动断开连接,以客户端主动断开连接为优。
第一次挥手:客户端打算断开连接,向服务器发送FIN(1)报文,FIN报文中会指定一个序列号 seq = x,之后客户端进入FIN_WAIT_1状态。
报文为:FIN = 1 ,序列号seq = x 。
第二次挥手:服务器收到释放报文(FIN)后,就向客户端发送ACK(x + 1,应答报文。同时发送 seq = y。服务器进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态,客户端到服务器的连接释放。客户端收到来自服务器的ACK应答报文段后,进入FIN_WAIT_2状态。
报文为:ACK = 1 , 序列号seq = y, 确认序列号ack = x + 1。
第三次握手:服务器也打算断开连接,向客户端发送连接释放(FIN)报文段,之后服务器进入LASK_ACK(最后确认)状态,等待客户端的确认。
报文为:FIN=1,ACK=1,序列号seq=m,确认序列号ack=u+1。
第四次握手:客户端收到来自服务器的连接释放(FIN)报文段后,会向服务器发送一个ACK应答报文段。
报文为:ACK = 1 , seq = u + 1 , ack = m + 1
之后客户端进入TIME_WAIT(时间等待)状态,服务器收到ACK应答报文段后,服务器就进入CLOSE(关闭)状态,到此服务器的连接已经完成关闭。
客户端处于TIME_WAIT状态时,此时的TCP还未释放掉,需要等待2MSL后,客户端才进入CLOSE状态。
(5)TCP的滑动窗口机制及重传机制
加入A发送了一个数据包,需要等到接收到B的确认报文后,才可以继续发送下一个报文是不是效率就比较慢。所以就引入了滑动窗口。
滑动窗口的本质:在发送方开启一个数据缓冲区,可以一次性发送n个报文,并放到缓冲区里面,接收端收到这些收据后,会给发送方一个应答。发送方等收到接收端的确认后,再讲数据从缓冲区删掉。一次性可以发送的最大报文数n就被成为窗口大小。
注意:窗口大小是发送方决定的,如果一次发送n条数据,而服务器此时只能处理m(m < n)条数据,此时是不是就会出问题。所以窗口大小是接收方根据自己的处理能力决定的。
那么一次性传多个报文,当遇到丢包怎么办?——TCP确认重传机制
- 比如A一次发了0~1000的报文给B,那么B给出的应答就是1001,表示前面1000个数据已经收到了,下一个报文应该是1001。
- 这时A又连续发10002000和20003000的报文给B,但是10002000的报文丢了,B没有收到。而收到了20003000的数据,那么接下来三次给A的应答都将是1001,表示应该为1001的数据丢失了。
- A后面连续三次收到了3次来自B的形同的响应1001,就知道1001~2000的数据丢失了,就会重传
(6)发送方窗口
接收窗口被划分为4个部分:
- 数据已被发送并且接收到ACK
- 数据已被发送但没有接收到ACK
- 数据未发送但在接收方处理能力范围之内
- 数据未发送并且不在接收方处理能力范围之内
窗口是如何滑动的?
-
当接收方返回4个确认应答,那么发送窗口就向右移动4个位置,同时窗口的每个部分都在同时变化.
-
这里注意如果发送方一下把数据全部发送,可用窗口大小就为0,那么就无法再次发送数据,需要等待接收方确认应答腾出窗口大小才能发送数据
(7)接收方窗口
接收窗口分为3个部分
- 已经成功接收,并且已经被接收方确认的数据
- 还没有收到的数据,但是可以接收
- 没有接收到的数据,还不可以被接收
接收的窗口大小与发送的窗口大小是完全相等的么?
可以认为是约等于的关系,把数据放到接收缓冲区里面还需要应用进程来进行读取,如果应用进程读取数据过快,接收缓冲区很快就空了,接收窗口很快就空出来,这时还要将新窗口的大小需要通过TCP的Windows字段告诉我们,这个传输过程存在时延迟,所以不是完全相等的.
3、TCP常见问题
(1)什么是半连接队列?
服务器第一次收到客户端的连接请求SYN时,会进入待连接状态SYN_RCVD。还没有完全建立连接。然后将此连接放入到一个队列里,这就是半连接对列。
(2)什么是自动重传?
当客户端法送了SYN请求后,如果迟迟没有收到服务器的回复,就会不断的重新发送连接请求。当重传次数到达系统规定的最大重传次数时,就会从半连接状态中删除。重传的时间间隔一般呈指数增加,比如:1s、2s、4s、8s……
(3)ISN(Initial Sequence Number)是固定的吗?
建立连接的初始序列不能是固定的。比如A用seq = 1向B发起了连接请求,当连接后,使用seq=1向B发送了100k数据,假设此时网络出故障了,这100k数据没有阻塞在网络中。刚好A重启了,之后又以seq = 1连接B,向B发了200K数据。此时,之前的100k数据也到达了B端。但是这时B还将这100k数据当做是新连接之后发的数据,是不是就有问题了。
可以避免数据乱序问题
(4)三次握手过程中可以携带数据吗?
第三次是可以的,但是前两次不行,因为前两次不知道对方的状态,比如此时服务器cpu已经满了,但是客户端还恶意的不断去发送大量数据,服务器就会分配资源来存储处理,可能会导致服务器崩溃。而最后一次是知道对方状态的,所以可以携带数据
(6)SYN攻击是什么?
服务端的连接是在第二次挥手时建立的,客户端是在第三次建立的。如果有客户端使用不存在的IP地址,向同一台服务器不断的发大量的SYN连接请求,服务器就会不停的回复确认报文,由于地址是不存在的,所以服务端每次发送的报文都不会得到确认,就会一直重传直到次数达到最大值。这就导致浪费大量的服务器资源,而使得正常的连接得不到资源而被丢弃。这就是洪泛攻击。
防止洪泛攻击的方法:
-
增大最大半连接数
-
缩短超时时间
-
SYN cookies技术
-
SYN cookies技术
服务器在第二次连接的时候,会将连接加入到半连接对列,等收到确认报文后,从半连接对列删除后,才认为建立成功。而开启SYN cookies不需要半连接对列,也会建立连接,具体做法是:
第二次挥手时,服务器会根据当前的状态,算出一个cookies值发给客户端,客户端在发送确认报文时,会携带这个值,服务器收到后进行校验,校验成功就会连接成功。
(7)挥手为什么需要四次?
当客户端的数据发送完后,发起断开连接请求,当收到服务端的确认后,就可以断开客户端的连接。但是此时还可以接收到服务器的数据。此时处于半关闭状态。但是此时服务器可能还有数据没有发送完成,所以等到服务器发完数据后,再向客户端发起断开连接请求。收到确认报文后,才会断开连接。
(8)四次挥手释放连接时,等待2MSL的意义?
MSL表示报文再网络环境中能存在的最长时间。如果第四次挥手后,客户端直接关闭,而它发出的确认报文丢失了,服务器就会因为收不到这个报文而等待。所以第四次挥手后,不能直接关闭,如果发出去的确认服务端没有收到,服务端就会重新进行第三次挥手,客户端再次做出确认报文。
(9)TIME_WAIT状态过多有什么危害?
浪费系统资源,如果服务端的TIME_WAIT状态过多,就会占用过多的端口资源得不到释放。占满了所有端口后,就无法创建新的连接了。
(10)如何解决TIME_WAIT状态过多?
- 最好是让客户端主动断开
- 对TIME_WAIT状态最大数做出限制,达到最大值时,将会被清理掉
- 短连接改为长链接