在学习 TCP 时,结合平时情况,想着是什么影响着系统的最大连接数,而 linux 中 tcp_max_syn_backlog 和 somaxconn 参数是每个进程独立设置还是共享一个总参数?
开始准备
tcp_max_syn_backlog 参数是控制半连接队列大小,由于暂时不知道怎么样让客户端三次握手的最后一步失败,测试不了半连接队列,暂时测试全连接队列
1. 设置全连接队列系统参数
echo 1 > /proc/sys/net/core/somaxconn
sysctl -p
cat /proc/sys/net/core/somaxconn
2. 服务端代码
/**
* 程序中不调用获取连接,只监听端口
* @date 2021-08-16 09:10
*/
public class NotAcceptServerSocketTest {
public static void main(String[] args) throws IOException {
if (args.length != 2) {
throw new RuntimeException("请传入启动参数, 第一个参数是监听端口, 第二个参数是 backlog");
}
int port = Integer.parseInt(args[0]);
int backlog = Integer.parseInt(args[1]);
/**
* backlog 全连接队列大小
* 该参数与系统参数 somaxconn 中取最小值
*/
ServerSocket serverSocket = new ServerSocket(port, backlog);
// 服务器只监听端口上的连接,不调用 accept() 方法读取连接到应用中处理
// serverSocket.accept();
while (true) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3. 客户端代码
/**
* 简单的客户端
* @date 2021-08-16 09:44
*/
public class SimpleSocketClientTest {
public static void main(String[] args) {
Socket socket = new Socket();
try {
// 设置自己服务器的 ip 地址和端口
socket.connect(new InetSocketAddress("127.0.0.1", 9110));
} catch (IOException e) {
e.printStackTrace();
}
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String s = scanner.nextLine();
try {
socket.getOutputStream().write(s.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4. 启动服务器代码
这里分别开启三个服务端,端口号分别是 9110 9120 9130。
服务端 somaxconn 参数分别是 1 4 1
java NotAcceptServerSocketTest 9110 1
java NotAcceptServerSocketTest 9120 4
java NotAcceptServerSocketTest 9130 3
5. 通过客户端去连接服务端
直接在本地环境 idea 中启动客户端代码,然后观察服务器连接状态。
客户端正常启动后,连接在限制内,可正常发送数据
超过连接限制,发送数据会报错
6. 服务器状态
状态处于 LISTEN 中时 Recv-Q 表示当前全连接队列数量,其他状态表示字节数。
连接详情
结论
通过观察得知,每个进程不是共享一个总参数,而是通过系统参数 somaxconn 或者程序中指定 backlog 参数,取其中的较小值,分别设置连接参数。也可以从图中看出,实际连接数大小是设置数 +1 。系统最大连接数还需要跟系统最大文件描述符和其他系统资源联系起来。