网站建设周期表,网络营销专业的就业方向,网站优化有哪些方法,公司seo目录
前言
一. 建立连接——三次握手
1. 三次握手过程描述
2. TCP连接建立相关问题
二. 释放连接——四次挥手
1. 四次挥手过程描述
2. TCP连接释放相关问题
三. TCP状态转换
结束语 前言
TCP——传输控制协议(Transmission Control Protocol)。是一种面向连接的传…目录
前言
一. 建立连接——三次握手
1. 三次握手过程描述
2. TCP连接建立相关问题
二. 释放连接——四次挥手
1. 四次挥手过程描述
2. TCP连接释放相关问题
三. TCP状态转换
结束语 前言
TCP——传输控制协议(Transmission Control Protocol)。是一种面向连接的传输层通信协议
什么是连接
TCP连接是指通过TCP协议在网络中建立的一种可靠的通信链路。TCP连接在应用层之间提供可靠高效的通信方式广泛应用于互联网上的各种应用如网页浏览电子邮件文件传输等。
建立连接在操作系统中是需要有对应的数据结构管理维护的。所以连接的建立维护都是有成本的
为什么要建立连接
更好的保证可靠性建立连接的过程其实就是让通信双方验证各自的发送能力和接收能力是否正常当前发送接收两端信道是否通畅。协商一些重要参数如序号初始值MSS是否启用SACK等等。
MSS和SACK可参看【计算机网络】TCP协议报头详解的选项部分
TCP建立连接通信断开连接的流程总图如下 一. 建立连接——三次握手 1. 三次握手过程描述
【1. 服务器初始化状态】
服务器端进程先创建传输控制块(TCB)socket()创建套接字listenfdbind()将套接字和端口号绑定服务器进程准备接收客户端的连接请求。然后服务器进程调用listen()函数使listenfd成为监听套接字后续连接都从监听套接字获取。此时服务器端进程处于监听(listen)状态紧接着调用accept()函数在listenfd套接字中等待客户的连接到来 服务器端进程调用函数顺序socket bind listen accept。当执行到accept函数时服务器进程会一直处于阻塞状态直到有客户连接请求到达才返回 【2. 客户端发起连接请求发送SYN同步报文段第一次握手】
客户端进程也创建传输控制块(TCB)socket()创建套接字然后向服务器端发送连接请求报文段这时请求报文段的首部标志位SYN1同时选择一个初始序号seqx这个初始序号x是随机产生的整数ISN。TCP规定SYN报文段(即SYN1的TCP报文段)不能携带数据但要消耗一个序号。此时客户端进程进入SYN-SENT(同步报文已发送)状态 客户端进程函数调用顺序socket connect。当客户端调用connect函数时操作系统会自动bind()客户端进程就会向服务器进程发送连接请求的SYN同步报文段 SYN1的报文段称为同步报文段 ISN(Initial Sequence Number)初始序列号 seq序号即当前发送的报文首字节的编号 【3. 服务器同意建立连接回复确认信息第二次握手】
服务器端进程收到连接请求报文若同意建立连接从listenfd中获取客户端信息并且由服务器端操作系统向客户端进程发送SYN报文段给出确认。在确认报文的首部中SYN1ACK1确认号ackx1 。同时也为自己选择一个初始序号seq y。这个确认报文也不能携带数据但同样要消耗一个序号。这时TCP服务器进入SYN-RCVD(同步报文已收到)状态 TCP协议规定只要接收方接收到数据必须给发送方发送确认报文——报文首部ACK标志位为1 ack确认号期望对方发送的下一个报文首字节的编号 【4. 客户端确认连接发送确认连接信息第三次握手】
客户端进程收到服务器进程的确认报文后还要向服务器进程的SYN报文给出确认。在确认报文首部ACK1确认号acky1序号seqx1。TCP标准规定ACK报文可以携带数据但如果不携带数据则不消耗序号。在这种情况客户端进程的下一个数据报文序号仍为seqx1。客户端在发送确认报文后认为连接成功建立先进入ESTABLISHED(已建立连接)状态。
当服务器端进程收到客户端发送的确认报文后认为连接成功建立进入ESTABLISHED(已建立连接)状态 上面给出的TCP连接建立过程叫做“三次握手”。注意上图服务器发送给客户端的报文也可以拆分为两个报文即先发送ACK1(ackx1)的确认报文再发送SYN1(seqy)的同步报文。客户端收到服务器端的同步报文段发送确认报文过程会变成“四次握手”但效果一样 2. TCP连接建立相关问题
问题1TCP建立连接可以只有2次握手吗
回答肯定不行。理由在握手过程中我们看到客户服务分别在最后一次握手建立连接。如果是两次握手那么最后的报文由服务器发送客户端接收 如此服务器就会先于客户端建立连接。这是万万不可的。
如果确认报文丢失那么服务器就会维护不成功的TCP连接会很容易遭受SYN洪水攻击即攻击者发送大量SYN请求两次握手会使得服务器对每个送达的SYN都建立连接如此会消耗大量资源容易导致服务器崩溃出现已失效的连接请求报文突然又传送到服务器端维护失效的连接 “已失效的连接请求报文”是如何产生的呢 假定一种异常情况客户端A发送的第一个连接请求报文在某个网络结点滞留了延误到客户端A认为该报文丢失失效本次连接失败时请求报文到达了服务器B。此时该请求报文已经失效但B并不知道所以给客户端A发送确认报文如果只有两次握手那么此时服务器B发出确认报文建立连接进入ESTABLISHED状态 由于A没有再发出建立连接的请求因此不会处理B的确认报文也不会向B发送数据。但B却认为连接成功建立并一直等待A发送数据浪费资源 所以握手次数绝不能是偶数次因为这样会使得服务器先建立连接将维护连接的成本嫁接给服务器 问题2TCP连接建立为什么需要3次握手
理由一奇数次握手客户端优先建立连接。
理由二防止已失效的连接请求报文突然又传送到了服务器端因而产生错误。
理由三三次握手是客户服务器验证双方信道通畅发送接收能力无误的最小成本 一二次握手验证了客户端的发送和接收能力二三次握手验证了服务器端的发送和接收能力 问题3在TCP连接建立过程中如果服务器一直收不到客户端的ACK确认报文会发生什么
操作系统会给每个处于SYN-RCVD状态的服务器进程设定一个计时器如果超过一定时间还没有收到客户端第三次握手的ACK确认报文将会重新发送第二次握手的确认报文直到重发达到一定次数才会放弃 问题4初始序列号ISN为什么要随机初始化
seq序号表示的是发送的TCP报文数据部分的起始字节位置服务器/客户端可以通过序号正确读取数据。如果不是随机分配起始序列号那么黑客就会很容易获取客户端与服务器之间TCP通信的初始序列号然后通过伪造序列号让通信主机读取到携带病毒的TCP报文发起网络攻击 问题5SYN洪水攻击如何解决
SYN洪水攻击攻击者在短时间内伪造大量不存在的IP地址向服务器不断地发送连接请求的SYN同步报文。服务器需要为每个请求发送SYN-ACK确认报文并等待客户端的确认但因为是不存在IP地址所以要像问题三中那样不断发送SYN-ACK确认报文直到重发到一定次数才会放弃但这样同样消耗资源。 解决方法
缩短SYN Timeout时间。由于SYN洪水攻击的效果取决于服务器上保持的半连接数这个值SYN攻击频率*SYN Timeout所以通过缩短从接收到SYN报文到确认这个报文失效并丢弃的时间可以成倍地降低服务器的载荷设置SYN Cookie。给每一个连接请求的IP地址分配一个Cookie如果短时间内连续收到某个IP地址的大量重复SYN报文就认定收到了攻击以后这个IP地址的报文将直接丢弃使用防火墙。SYN 洪水很容易就能被防火墙拦截
二. 释放连接——四次挥手
TCP连接的释放可以用“四次挥手”的过程来描述。数据传输结束后通信双方都可以释放连接。现在客户端和服务器都处于ESTABLISHED状态。释放连接的过程如下图所示 1. 四次挥手过程描述
【1. 客户端主动断开连接调用close(fd)发送释放连接的FIN报文第一次挥手】
客户端进程调用close(fd)关闭套接字操作系统发送释放连接的FIN结束报文并停止发送数据主动关闭TCP连接。在结束报文的首部标志位FIN1序号字段sequ等于前面已发送的数据的最后一个字节的序号1.此时客户端进入FIN_WAIT_1(终止等待)状态等待服务器发送确认报文。
TCP规定FIN报文即使不携带数据也要消耗一个序号。与SYN报文一样
【2. 服务器收到客户端发送的结束报文发出确认报文段第二次挥手】
服务器收到客户端发送的释放连接的FIN结束报文立即发送确认报文确认号acku1序号seqv等于服务器前面已发送的数据的最后一个字节的序号1。服务器进入CLOSE_WAIT(关闭等待)状态。TCP服务器进程此时通知上层应用程序客户端不向服务器发送数据了但服务器若有数据发送客户端仍要接收此时TCP连接处于半关闭(half-close)状态。
客户端收到服务器的确认报文后进入FIN_WAIT2(终止等待2)状态等待服务器发送的FIN结束报文
【3. 服务器调用close(connfd)关闭套接字释放连接发送FIN结束报文第三次挥手】
当服务器没有要向客户端发送的数据时其应用进程调用close(connfd)通知TCP释放连接向客户端发送FIN结束报文。结束报文中FIN1假定序号seqw(半关闭状态服务器可能还发送了一些数据)同时还必须重复上次已发送过的确认号acku1。此时服务器进程进入LAST_ACK(最后确认)状态等待客户端确认。
【4. 客户端收到服务器的FIN结束报文发送确认报文第四次挥手】
客户端在收到服务器的FIN结束报文后向服务器发送ACK确认报文。在报文首部中ACK1确认序号ackw1序号sequ1(第一次挥手的FIN报文消耗一个序号)。然后客户端进入TIME_WAIT(时间等待)状态
此时TCP连接还没有释放掉必须经过时间等待计时器(TIME_WAIT timer)设置的时间2MSL后A才进入CLOSED状态时间MSL(Maximum Segment Lifetime最长报文寿命)即一个TCP报文存活的最长时间。RFC793建议2分钟现在可以根据情况使用更小的MSL值。因此客户端进入TIME_WAIT状态要经过4分钟才进入CLOSED状态才可以建立下一个连接当客户端撤销相应的传输控制块TCB才结束这次TCP连接
服务器只要收到客户端的确认报文就进入CLOSED状态。同样服务器在撤销相应的传输控制块TCB后就结束此次TCP连接
可以发现先发起释放连接请求的一方后结束TCP连接 2. TCP连接释放相关问题
问题1为什么建立连接是三次握手关闭连接是四次挥手
首先建立连接也可以是四次握手中间的SYN和ACK可以分成两次报文。其次关闭连接中间服务器给客户端发送的确认报文和FIN结束报文也可以合并但可能服务器方还有数据需要传输FIN结束报文在上层调用close()时发送此时服务器已没有数据传输。 发送FIN报文只是表示本端不再继续发送数据但还可以接收数据。TCP通信时全双工的收到FIN报文只是关闭一个方向的连接此时TCP处于半关闭状态 问题2为什么客户端在TIME_WAIT需要等待2MSL才进入CLOSED状态
理由一保证客户端发送的最后一个ACK报文能到达对端保证可靠的终止TCP连接。因为如果出现网络拥塞该报文可能丢失因而会使LAST_ACK状态的服务器收不到确认报文而超时重传FIN报文而客户端能在2MSL时间内收到重传的FIN报文。接着客户端重传一次确认重新启动2MSL计时器。最后双方正常进入CLOSED状态
理由二防止已失效的连接请求报文出现在本次TCP连接。客户端在发送完最后一个ACK报文后再经过2MSL后就可以使本次TCP连接持续时间内所产生的所有报文都从网络上消散。这样可以使下一个新的TCP连接不会出现之前旧的请求报文 问题3TIME_WAIT状态何时出现TIME_WAIT会带来哪些问题
TIME_WAIT状态是主动发起关闭连接的一方在收到对方发送的FIN结束报文并本端发送ACK报文后的状态。
TIME_WAIT的引入是为了让TCP报文得以自然消散同时为了让被动关闭的一方能够正常关闭连接
服务器主动关闭连接短时间关闭大量客户端连接会出现大量TIME_WAIT状态此时TCB并没有释放占据大量的tuple(源IP地址、目的IP地址、协议号、源端口、目的端口)严重消耗着服务器的资源。客户端主动关闭连接短时间内大量的短连接会大量消耗客户端主机的端口号毕竟端口号只有65535个断开耗尽了后续就无法启用新的TCP连接了。 问题4解决TIME_WAIT状态引起的bind()函数执行失败
问题场景因为主动关闭连接最终会进入TIME_WAIT状态此时bind的IP地址端口号都没有释放重新启动服务会导致bind端口号失败。
解决方法可以使用setsockopt()函数设置socket描述符的SO_REUSEADDR选项该选项可以让端口号被释放后立即再次使用表示允许创建端口号相同但IP地址不同的多个socket描述符 问题5半连接半打开半关闭的区别半连接在TCP连接建立的三次握手中主动发起连接请求的一方不发最后一次的ACK确认报文使得服务器阻塞在SYN_RCVD(同步收到)状态
半打开如果TCP通信一方异常关闭(如断网断电进程被kill掉)而通信对端并不知情此时TCP连接处于半打开状态如果双方不进行数据通信是无法发现问题的。解决方法是引入心跳机制设置一个保活计时器(keepalive timer)以检测半打开状态检测到就发送RST复位报文重新建立连接
半关闭主动发起连接关闭请求的一方A发送了FIN结束报文段对端B回复了ACK确认报文段后B并没有立即发送本端的FIN结束报文段给A。此时A端处于FIN_WAIT-2结束等待2状态A仍然可以接收B发送过来的数据但是A已经不能再向B发送数据了。这时的TCP连接为半关闭状态。 补充 在Socket编程中服务器Listen的第二个参数 三次握手是操作系统自助完成的但服务器需要accept返回才会拿到客户端的连接信息。如果服务器没有accept这个连接就是全连接。backlog是全连接队列的容量-1。
Linux内核协议栈为TCP连接管理使用两个队列
半连接队列(用来保存SY_SENT和SYN_RECV状态的请求)全连接队列(accept队列用来保存处于ESTABLISHED状态但应用层没有调用accept取走的请求)
三. TCP状态转换
为了更清晰地看出TCP连接的各种状态之间的关系下图给出了TCP的状态转换示意图。
说明紫色框框是TCP状态红色是服务器进程的正常状态转换蓝色是客户端进程的正常状态转换黑色是异常变迁即出现问题时的状态转换。 服务端状态转化
【CLOSE - LISTEN】服务器端调用listen后进入LISTEN状态等待客户端连接【LISTEN - SYN_RCVD】一旦监听到连接请求(同步报文段)就将该连接放入内核等待队列并向客户端发送SYN确认报文【SYN_RCVD - ESTABLISHED】服务端一旦受到客户端的确认报文进入ESTABLISHED状态可以进行读写数据【ESTABLISHED - CLOSE_WAIT】客户端主动关闭连接(调用close)服务器会受到结束报文服务器返回确认报文并进入CLOSE_WAIT【CLOSE_WAIT - LAST_ACK】进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据)当服务器调用close关闭连接时会向客户端发送FIN结束报文进入LAST_ACK状态等待客户端发送FIN结束报文的ACK确认报文【LAST_ACK - CLOSED】服务器收到了对FIN结束报文的ACK确认报文释放连接撤销传输控制块TCB释放相应的连接管理资源 客户端状态转化
【CLOSED - SYN_SENT】客户端调用connect()发送SYN同步报文段【SYN_SENT - ESTABLISHED】connect()调用成功进入ESTABLISHED状态开始读写数据【ESTABLISHED - FIN_WAIT1】客户端主动调用close()向服务器发送FIN结束报文段同时进入FIN_WAIT1状态【FIN_WAIT1 - FIN_WAIT2】客户端收到服务器发送的对FIN结束报文的ACK确认报文则进入FIN_WAIT2状态开始等待服务器的FIN结束报文【FIN_WAIT2 - TIME_WAIT】客户端收到服务器发送的FIN结束报文进入TIME_WAIT状态并发送最后一个ACK确认报文【TIME_WAIT - CLOSED】客户端等待2MSL时间才会进入CLOSED状态释放连接资源
结束语
本篇博客到此结束感谢看到此处。 欢迎大家纠错和补充 如果觉得本篇文章对你有所帮助的话不妨点个赞支持一下博主拜托啦这对我真的很重要。