TCP/IP相关

TCP/IP相关

1. 定义

  • IP协议

    • IP 协议实际上是用来查找地址的,而它对应的层级也是网络层,也可以称之为网际互联层,区别不大。

  • TCP协议

    • TCP 协议是用来规范传输规则的,和IP 协议是不同的,而它对应的层级是传输层,也就是IP去寻找地址,把所有的传输任务都交给TCP,而TCP相当于一个快递员的角色。

2. 三次握手

  • 序号

    • seq:sequence number 的缩写,即序号。seq表示的则是自己传递的序号,TCP在传输的时候,其中每一个字节,都会有一个序号,发送数据的时候,会把第一个数据的第一个序号发送给对方,就是看到的第一步,而接收的这一方面,会按照这个序号来检查是否是一个连接完整的数据,是完整的话就继续,不完整的话就重新发送。保证数据完整性不被破坏。

    • ack: 注意是小写的 acknoledgement number的缩写 表示确认号 ,要和ACK(确认位)区分 ,接收端用它来给发送端返回接受消息的数据信息,而这时候,它的值就是表明我想接收下一个数据包了。而这个值就是下一个数据包的开始的序号,而这个ack所代表的值的序号前面的数据都已经接受成功了。

    • ACK确认位: 只有当ACK=1的时候ack才会起到作用,而在我们第一次请求的时候,是没有需要确认的接受的数据的,这个时候ACK=0,正常通信下ACK=1.

    • SYN: 同步位 ,作用是用于建立连接时同步序号,刚建立连接的时候,ACK=0这时ack就不起作用,当接收端收到SYN=1的报文的时候,会将ack设置为接收到的seq+1的值,这时候的ack的值就是根据SYN来设置的。

    • FIN:终止位,在本图没有体现,在四次挥手的时候能完全体现出来。而它是用来在数据传输都完成之后来释放连接的。

  • 上图解析:

    • 第一次握手(SYN=1,seq=x)

      • 客户端发送一个TCP的SYN标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号X,保存在包头的序列号(seq)中。发送完毕后,客户端进入SYN_SEND状态

    • 第二次握手(ack=y+1,ACK=1,seq=y,SYN=1)

      • 服务器发回确认包(ACK)应答。即SYN和ACK标志位都为1。服务器端选择自己ISN序列号,放到seq域中,同时将确认序号ack设置为客户的ISN加1,即y+1。发送完毕后,服务端进入SYN_RCVD状态

    • 第三次握手(ack=y+1,ACK=1)

      • 客户端再次发送确认包(ACK),SYN标志位为0,ACK标志位为1,并且把服务器发来的ACK序号字段+1,放在ack中返回。发送完毕后,客户端进入ESTABLISHED状态,当服务端接收到这个包时也会进入ESTABLISHED状态,TCP握手结束。

3. 四次挥手

  • 流程解读:

    • 第一次挥手(FIN=1,seq=x)

      • 假如客户端想要关闭连接,客户端发送一个FIN标志位置为1的包,表示自己已经没有数据可以发送了,但是任然可以接受数据,发送完毕后,客户端进入FIN_WAIT_1状态

    • 第二次挥手(ACK=1,ack=x+1)

      • 服务器端接收到客户端发送的FIN包,发送一个确认包,表明自己接受到了客户端关闭连接的请求但是服务端还没有准备好关闭连接。发送完毕后,服务器端进入CLOSE_WAIT状态,客户端收到这个确认包后,进入FIN_WAIT_2状态等待服务器关闭连接。

    • 第三次挥手(FIN=1,seq=y)

      • 服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN值为1。发送完毕后,服务器端进入LAST_ACK状态 ,等待来自客户端的最后一个ACK。

    • 第四次挥手(ACK=1,ack=y+1)

      • 客户端收到服务端的关闭请求时,发送一个确认包,并且进入TIME_WAIT状态,等待可能出现的要求重传的ACK包。

      • 服务器端接收到这个包后,关闭连接,进入CLOSED状态

      • 客户端等待了某个固定时间(两个最大段生命周期,2MSL,2Maximum Segment Lifetime)之后,没有收到服务器端的ACK,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入CLOSED状态。两次后会重传直到超时。如果多了会有大量半链接阻塞队列

4. 为什么连接三次握手,而断开是四次挥手呢

  • 这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示客户端不再发送数据,但是还能接受数据,服务端是否现在关闭数据发送通道需要上层应用决定,因此ACK和FIN一般分开发送。

5. 服务器保持了大量TIME_WAIT状态

  • 原因

    • TIME_WAIT是主动关闭连接的一方保持的状态,对于爬虫服务器来说他本身就是“客户端”,在完成一个爬取任务之后,他就 会发起主动关闭连接,从而进入TIME_WAIT的状态,然后在保持这个状态2MSL(max segment lifetime)时间之后,彻底关闭回收资源。

    • 查看服务器所有连接状态的命令

      netstat -n|awk '/^tcp/{++S[$NF]}END{for (key in S) print key,S[key]}'
  • 为什么?

    • 防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)

    • 可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。

  • 解决方案

    • 编辑文件/etc/sysctl.conf,加入以下内容:

      net.ipv4.tcp_syncookies = 1
      net.ipv4.tcp_tw_reuse = 1
      net.ipv4.tcp_tw_recycle = 1
      net.ipv4.tcp_fin_timeout = 30

6. 服务器保持了大量CLOSE_WAIT状态

  • 原因

    • 就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直 被程序占着。

    • 比如说

      服务器A是一台爬虫服务器,它使用简单的HttpClient去请求资源服务器B上面的apache获取文件资源,正常情况下,如果请求成功,那么在抓取完 资源后,服务器A会主动发出关闭连接的请求,这个时候就是主动关闭连接,服务器A的连接状态我们可以看到是TIME_WAIT。如果一旦发生异常呢?假设 请求的资源服务器B上并不存在,那么这个时候就会由服务器B发出关闭连接的请求,服务器A就是被动的关闭了连接,如果服务器A被动关闭连接之后程序员忘了 让HttpClient释放连接,那就会造成CLOSE_WAIT的状态了。

  • 解决方案

    • 此问题一般是由于程序代码编写问题导致的,查代码吧

猜你喜欢

转载自blog.csdn.net/wkfyynh/article/details/107936594
今日推荐