接下来我们看如果连接队列满了的话,内核会如何处理。先写个测试程序,构造连接队列满的情况。测试程序说明如下:
1、服务器端地址为192.168.1.188,监听端口为80;客户端地址为192.168.1.192
2、服务器端在80端口建立一个监听套接字,listen()的backlog参数设置的是300,将sysctl_max_syn_backlog和sysctl_somaxconn系统配置都调整为4096,特别要注意的是服务器端一定不要调用accept()来接收连接,在建立起监听后,让进程睡眠等待。关键代码如下:
........
if ((ret = listen(fd, 300)) < 0) {
perror("listen");
goto err_out;
}
/* wait connection */
while (1) {
sleep(3);
}
........
3、客户端通过一个循环发起1000个连接请求,为了后面进一步的分析,在第401连接建立后打印输出其本地端口,并且发送了两次数据。关键代码如下:
......
ret = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
if (ret < 0) {
fprintf(stderr, "connect fail in %d times, reason: %s.\n", i + 1, strerror(errno));
return -1;
}
connections[i] = fd;
fprintf(stderr, "Connection success, times: %d, connections: %d.\n", i + 1,
check_connection_count(connections, i + 1));
if (i == 400) {
len = sizeof(sa);
ret = getsockname(fd, (struct sockaddr *)&sa, &len);
if (ret < 0) {
fprintf(stderr, "getsockname fail, ret=%d.\n", ret);
return -1;
}
fprintf(stderr, "connecton %d, local port: %u.\n", i,ntohs(sa.sin_port));
str = "if i can write ,times 1";
ret = write(fd, str, strlen(str));
fprintf(stderr, "first writ in connection %d, ret = %d.\n", i, ret);
str = "if i can write ,times 2";
ret = write(fd, str, strlen(str));
fprintf(stderr, "second writ in connection %d, ret = %d.\n", i, ret);
}
.......