Java面试基础之TCP连接以及其优化
作者:jianjianqq 发布时间:2023-10-02 17:43:51
前言
作为一个后端程序员,网络连接这块是一个绕不过的砍,当你在做服务器优化的时候,网络优化也是其中一环,那么作为网络连接中最基础的部分-TCP连接你了解吗?今天我们来仔细看看这个部分。
TCP建立连接-三次握手
详解
客户端和服务器还未建立连接,但服务器一般处于listen状态
客户端主动建立连接,向服务器发送SYN报文,客户端变为SYN_SENT状态
服务器收到客户端发送的报文,也回了一个SYN报文,包含了一个ack。此时,服务器变为SYN_RCVD状态
客户端收到了服务器发送的SYN报文,确认了ack,它将向服务器发送一个ACK报文。此时,客户端变为ESTABLISHED
服务器收到客户端的ACK报文,确认了ack。此时,服务器也变为ESTABLISHED
服务器和客户端可以正常通信了
其中步骤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断开连接-四次挥手
详解
客户端与服务器端正常传输数据
客户端主动断开连接,向服务器端发送FIN报文,客户端变为FIN_WAIT1状态
服务器收到客户端的FIN后,向客户端发送ACK报文,服务器变为CLOSE_WAIT状态
客户端收到服务器的ACK报文后,客户端变为FIN_WAIT2状态
服务器向客户端发送FIN报文,服务器变为LAST_ACK状态
客户端收到服务器发送的FIN报文后,向服务器发送ACK报文,客户端变为TIME_WAIT状态
服务器收到客户端的ACK报文后,服务器变为CLOSED状态
客户端经过2MSL(max segment lifetime,报文最大生存时间)时间后,也变为CLOSED状态
其中,步骤2、3、5、6即为4次挥手。
TIME_WAIT状态及其优化
看完之后,大家想必会有一个疑问,为什么TIME_WAIT状态需要保持2MSL?因为这可以保证至少一次报文的往返时间内,端口是不可复用的。
假设TIME_WAIT状态的持续时间很短,我们来模拟下面这种场景:
客户端向服务器端发送了三条报文,其中第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


猜你喜欢
- mac版本:点击Finder,在应用程序中找到android studio----->Contents文件夹----->bin文
- 本期文章源码:GitHub一文彻底搞懂《并查集》!概念并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。
- 本文实例讲述了Android编程实现Listview点击展开和隐藏的方法。分享给大家供大家参考,具体如下:代码较多,所以找关键点大家贴出来,
- 最近项目需要,需要做一个BMI指数的指示条,先上效果图: BMI指数从18到35,然后上面指示条的颜色会随着偏移量的变化而改变,数字显示当前
- 本文实例讲述了C#使用GZipStream解压缩数据文件的方法。分享给大家供大家参考。具体分析如下:GZipStream用于从一个流读取数据
- 由于在项目中要实现用户注册的邮箱激活以及忘记密码重置密码功能,所以通过查阅资料做了一个简单的设计和实现。邮箱激活背景:几乎每个网站或论坛之类
- 前言: 之前安装了Ubuntu 18.04,结果在安装Codeblocks / VScode还是安装gcc,c/c++的时候出现了一堆错误(
- 从C#3.0开始,可以使用lambda表达式把实现代码赋予委托。lambda表达式与委托(https://www.jb51.net/arti
- 本文运用图片给大家介绍了C#如何检查foreach判读其是否为null,我们下面话不多说,直接来看内容吧。1、foreach遍历列表或数组时
- 前言我们程序员在开发的时候经常会遇到各种各样的 BUG 问题,其中大部分是业务逻辑异常,还有一些是代码书写不规范造成的异常例如:NullPo
- 本文为大家分享了Swing单选按钮和复选框的使用方法,供大家参考,具体内容如下JRadioButton构造函数:JRadioButton()
- Android 破解视频App去除广告功能作为一个 * 丝程序猿也有追剧的时候,但是当打开视频app的时候,那些超长的广告已经让我这个 * 丝无法忍
- 通过URL来获取网络资源并下载资源简单实例:package com.android.xiong.urltest; import java.i
- Invoke Phing targets这个插件主要是读取xml形式包括自动化测试打包部署的配置文件,然后根据流程走下来。用ph
- Task的应用Task的MSDN的描述如下:【Task类的表示单个操作不会返回一个值,通常以异步方式执行。Task对象是一种的中心思想基于任
- 一、同步问题提出线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。例如:两个线程ThreadA、ThreadB都操作同一个对
- 1. Spark中的RDDResilient Distributed Datasets(弹性分布式数据集)Spark中的最基本的抽象有了RD
- 一、题目描述题目实现:获取远程服务器和客户机的IP地址和端口号。二、解题思路创建一个服务器类:ServerSocketFrame,继承JFr
- 累加数累加数 是一个字符串,组成它的数字可以形成累加序列。一个有效的 累加序列 必须 至少 包含 3 个数。除了最开始的两个数以外,序列中的
- 因为公司业务需要,需要把性能日志和业务日志分开打印,用elk收集处理,所以需要对不同的业务的日志,打印到不同文件。使用的是spring bo