Java面试基础之TCP连接以及其优化

作者:jianjianqq 时间:2023-10-02 17:43:51 

前言

作为一个后端程序员,网络连接这块是一个绕不过的砍,当你在做服务器优化的时候,网络优化也是其中一环,那么作为网络连接中最基础的部分-TCP连接你了解吗?今天我们来仔细看看这个部分。

TCP建立连接-三次握手

详解

Java面试基础之TCP连接以及其优化

  1. 客户端和服务器还未建立连接,但服务器一般处于listen状态

  2. 客户端主动建立连接,向服务器发送SYN报文,客户端变为SYN_SENT状态

  3. 服务器收到客户端发送的报文,也回了一个SYN报文,包含了一个ack。此时,服务器变为SYN_RCVD状态

  4. 客户端收到了服务器发送的SYN报文,确认了ack,它将向服务器发送一个ACK报文。此时,客户端变为ESTABLISHED

  5. 服务器收到客户端的ACK报文,确认了ack。此时,服务器也变为ESTABLISHED

  6. 服务器和客户端可以正常通信了

其中步骤2~4就是三次握手,那么为什么需要三次握手呢?为什么不是一次或者两次握手呢?

首先,我们需要知道,只有当服务器和客户端都能确保自己能够发消息和接收消息,这次网络通信才算成功的。

步骤2的作用是让服务器知道了自己是可以接收消息的。

步骤3的作用是让客户端知道自己发送消息和接收消息的功能是OK的,发送消息的能力是通过服务器返回的ack=x+1确认的,因为这个值基于当初客户端发送的消息seq=x。接收消息的能力是因为收到了服务器的返回。

步骤4的作用是让服务器端知道自己发送消息的能力是OK的(和步骤3类似)。

linux查看

linux服务器可以利用netstat -anp | grep tcp命令,查看服务器上各个端口和应用的连接状态。

你还可以通过修改linux的配置文件/etc/sysctl.conf,调整各个状态的数量

SYN_SENT状态相关

主动建立连接时,发SYN(步骤2)的重试次数


nct.ipv4.tcp_syn_rctries = 6

建立连接时的本地端口可用范围


net.ipv4.ip_local_port_range = 32768 60999

SYN_RCVD状态相关

SYN_RCVD状态连接的最大个数


net.ipv4.tcp_max_syn_backlog

被动建立连接时,发SYN/ACK(步骤3)重试次数


net.ipv4.tcp_synack_retries

说完了TCP建立连接,接下来,我们再来看看TCP正常断开连接的过程

TCP断开连接-四次挥手

详解

Java面试基础之TCP连接以及其优化

  1. 客户端与服务器端正常传输数据

  2. 客户端主动断开连接,向服务器端发送FIN报文,客户端变为FIN_WAIT1状态

  3. 服务器收到客户端的FIN后,向客户端发送ACK报文,服务器变为CLOSE_WAIT状态

  4. 客户端收到服务器的ACK报文后,客户端变为FIN_WAIT2状态

  5. 服务器向客户端发送FIN报文,服务器变为LAST_ACK状态

  6. 客户端收到服务器发送的FIN报文后,向服务器发送ACK报文,客户端变为TIME_WAIT状态

  7. 服务器收到客户端的ACK报文后,服务器变为CLOSED状态

  8. 客户端经过2MSL(max segment lifetime,报文最大生存时间)时间后,也变为CLOSED状态

其中,步骤2、3、5、6即为4次挥手。

TIME_WAIT状态及其优化

看完之后,大家想必会有一个疑问,为什么TIME_WAIT状态需要保持2MSL?因为这可以保证至少一次报文的往返时间内,端口是不可复用的。

假设TIME_WAIT状态的持续时间很短,我们来模拟下面这种场景:

Java面试基础之TCP连接以及其优化

  • 客户端向服务器端发送了三条报文,其中第3条报文卡在网络中,服务器只收到了前两条,向客户单发送ACK=2,客户端重新发送第三条报文。

  • 服务器主动发送FIN报文,客户端收到后发送FIN、ACK,服务器端收到后发送ACK并进入TIME_WAIT状态(假设这个状态很短)。

  • 现在服务器又再次和客户端建立连接,三次握手之后开始发送正常数据,结果之前卡住的第三条报文,现在终于发送到服务器,但服务器也不知道该如何处理这条报文。

因此这也是TIME_WAIT状态需要保持2MSL的原因,如果这么长时间也没有收到报文,即使有正确的报文从客户端发出,也已经过期了,因此不会影响到之后的通信。

但这同样也会带来一个问题,TIME_WAIT状态保持的时间较长,假设服务器端有大量TIME_WAIT状态的TCP连接,就相当于白白浪费掉大量的服务器资源(端口)。此时,我们可以通过修改以下配置进行服务器调优:


net.ipv4.tcp_tw_reuse = 1
  • 开启后,作为客户端时新连接可以使用仍然处于TIME_WAIT状态的端口

  • 由于timestamp的存在,操作系统可以拒绝迟到的报文(例如上面说的第三条报文),可以利用以下配置:


net.ipv4.tcp_timestamps = 1

其他状态的优化

CLOSE_WAIT状态

如果服务器端有大量CLOSE_WAIT状态的连接,很有可能是应用进程出现bug,没有及时关闭连接。

FIN_WAIT1状态

调整发送FIN报文的重试次数,0相当于8


net.ipv4.tcp_orphan_retries = 0

FIN_WAIT2状态

调整保持在FIN_WAIT2状态的时间


net.ipv4.tcp_fin_timeout = 60

总结

看到这里,想必你应该对TCP连接有了一个大致的了解。现在服务器大多都用了nginx做了负载均衡,因此,我们可能需要在此基础上了解一些nginx相关的配置原理,这样应该会对我们的服务器性能调优会有更大的帮助。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

来源:https://www.cnblogs.com/death00/p/11510827.html

标签:java,tcp,连接
0
投稿

猜你喜欢

  • Android开发导入项目报错Ignoring InnerClasses attribute for an anonymous inner class的解决办法

    2023-05-16 13:02:45
  • JDK动态代理与CGLib动态代理的区别对比

    2022-10-22 10:04:21
  • Java正确使用访问修饰符的姿势

    2021-10-11 09:52:50
  • 使用注解@Validated和BindingResult对入参进行非空校验方式

    2022-09-16 11:30:44
  • centos 安装java环境的多种方法

    2023-08-10 16:01:37
  • Android编程判断网络连接是否可用的方法

    2021-06-25 20:25:03
  • Mybatis中TypeAliasRegistry的作用及使用方法

    2023-06-27 19:21:32
  • springboot2.x 接入阿里云市场短信发送的实现

    2023-09-20 23:03:57
  • Mybatis Plus中的流式查询案例

    2023-08-18 16:35:13
  • android使用SoundPool播放音效的方法

    2023-07-08 01:16:29
  • Android小程序实现简易QQ界面

    2023-07-03 20:29:52
  • java批量修改文件后缀名方法总结

    2022-03-15 15:46:04
  • Android简单实现圆盘抽奖界面

    2022-07-25 08:35:27
  • Java编写迷宫小游戏

    2021-08-06 12:53:33
  • C#生成随机验证码代码分享

    2023-07-17 21:22:26
  • 如何在Springboot实现拦截器功能

    2023-01-10 01:11:38
  • Spring Boot项目维护全局json数据代码实例

    2023-04-17 23:24:10
  • Android App开发中自定义View和ViewGroup的实例教程

    2021-06-11 08:58:03
  • 详解SpringBoot注解读取配置文件的方式

    2023-08-05 02:51:16
  • java实现简单登录界面的实战过程

    2022-02-07 20:19:51
  • asp之家 软件编程 m.aspxhome.com