Too many open files测试

 

目录

 

背景

验证方式

代码

sever端代码

client端代码

验证

默认(1024)配置

分析

报文

修改配置为1048

总结


背景

linux下一切皆文件,所以一个tcp连接也是一个文件。

linux对每个进程打开的最大文件数是有限制的。通过ulimit -a查看:默认的大小是1024。一个打开的文件占用一个文件描述符,而且是顺序增加的整数值。

本文通过例子来验证一下。

验证方式

写一个TCP server端: 接收网络连接

写一个TCP client端:只建立连接

代码

sever端代码


#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdio.h>

int main(int argc, char **argv) {
    int listenFD = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in bindAddr;
    bzero(&bindAddr, sizeof(bindAddr));

    bindAddr.sin_family = AF_INET;
    bindAddr.sin_port = htons(8080);
    bindAddr.sin_addr.s_addr = htonl(INADDR_ANY);


    int bindRet = bind(listenFD, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
    if (bindRet != 0) {
        perror("bind失败");
        return 1;
    }

    listen(listenFD, 10000);
    int connCount = 0;
    printf("已监听,等待连接.\n");
    int failCount = 0;
    while (1) {
        struct sockaddr_in connAddr;
        socklen_t connAddrSize = sizeof connAddr;
        bzero(&connAddr, connAddrSize);
        int connfd = accept(listenFD, (struct sockaddr *) &connAddr, &connAddrSize);
        if (connfd < 0) {
            failCount++;
            perror("accept失败.");
            if (failCount > 10) {
                printf("accept失败次数大于10,程序退出\n");
                return 2;
            }
            continue;
        }
        connCount++;
        printf("接收第[%d]个连接%d,端口:%d\n", connCount, connfd, ntohs(connAddr.sin_port));
    }

}

client端代码


#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdio.h>

int main(int argc, char **argv) {
    int listenFD = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in bindAddr;
    bzero(&bindAddr, sizeof(bindAddr));

    bindAddr.sin_family = AF_INET;
    bindAddr.sin_port = htons(8080);
    bindAddr.sin_addr.s_addr = htonl(INADDR_ANY);


    int bindRet = bind(listenFD, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
    if (bindRet != 0) {
        perror("bind失败");
        return 1;
    }

    listen(listenFD, 10000);
    int connCount = 0;
    printf("已监听,等待连接.\n");
    int failCount = 0;
    while (1) {
        struct sockaddr_in connAddr;
        socklen_t connAddrSize = sizeof connAddr;
        bzero(&connAddr, connAddrSize);
        int connfd = accept(listenFD, (struct sockaddr *) &connAddr, &connAddrSize);
        if (connfd < 0) {
            failCount++;
            perror("accept失败.");
            if (failCount > 10) {
                printf("accept失败次数大于10,程序退出\n");
                return 2;
            }
            continue;
        }
        connCount++;
        printf("接收第[%d]个连接%d,端口:%d\n", connCount, connfd, ntohs(connAddr.sin_port));
    }

}

​

验证

默认(1024)配置

服务器端输出:

[root@localhost c]# ./a.out
已监听,等待连接.
接收第[1]个连接4,端口:3516
接收第[2]个连接5,端口:3517
接收第[3]个连接6,端口:3518
接收第[4]个连接7,端口:3519
接收第[5]个连接8,端口:3520
...省略中间的
接收第[1016]个连接1019,端口:54352
接收第[1017]个连接1020,端口:54353
接收第[1018]个连接1021,端口:54354
接收第[1019]个连接1022,端口:54355
接收第[1020]个连接1023,端口:54356
accept失败.: Too many open files
accept失败.: Too many open files
accept失败.: Too many open files

客户端输出:

connect函数返回小于0的值,并且perror的信息是:Connection refused(后面从报文看服务器端返回RST报文,重置了连接)

第1019个连接成功
第1020个连接成功
第1021个连接成功
连接失败!0
连接失败!1
连接失败...: Connection refused
连接失败...: Connection refused
连接失败...: Connection refused

分析

服务器端接收了1020个连接后就accept失败,最后一个连接的描述符是: 1023。之前通过ulimit -a查看的是1024。这里为什么只有1020个连接呢?

因为每个进程默认都会打开标准输入、标准输出、标准错误输出,占用了0、1、2。在c语言的标准库unistd.h中定义,代码如下:

/* Standard file descriptors.  */
#define	STDIN_FILENO	0	/* Standard input.  */
#define	STDOUT_FILENO	1	/* Standard output.  */
#define	STDERR_FILENO	2	/* Standard error output.  */

加上这3个,也才1023个,还差一个呢?

差的那一个就是我们在server端的代码中创建的监听套接字,listenFD。

报文

通过抓包可以看到,服务端达到too many open files后,协议栈会发送RST报文,直接重置连接。

 

 

修改配置为1048

使用 ulimit -n 1048 临时修改

服务器端输出:

接收第[1040]个连接1043,端口:62788
接收第[1041]个连接1044,端口:62789
接收第[1042]个连接1045,端口:62790
接收第[1043]个连接1046,端口:62791
接收第[1044]个连接1047,端口:62792
accept失败.: Too many open files
accept失败.: Too many open files
accept失败.: Too many open files
accept失败.: Too many open files

这里为什么是1044而不是1048呢?和上面的原因是一样的,你能想起来是为什么?

 

总结

  • linux下每个进程能创建的socket数是有限制的,可以通过ulimit命令来查看和临时修改,如果需要永久修改需要修改配置文件。
  • 默认是1024.但是只能接受1020个客户端连接。因为标准输入、标准输出、标准错误输出、listen的socket会占用4个。
  • 如果某个连接关闭了,那么连接描述符是可以复用的。
  • 如果超过open files的阈值:
    • 服务器端 accept函数,返回失败,错误信息是 Too many open files.
    • 客户端connect函数,返回失败,错误信息是 Connection refused.
    • 服务器端给客户端返回RST报文,重置连接。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值