linux文件描述符限制及使用详解

背景

最近调试一款网关设备,它部署在客户端和服务端之间。在工作时,它同时接收来自客户端的连接,同时又向服务端建立连接。

网关在完全接收来自客户端的数据后,会校验数据合法性,只有数据合法,网关才会向服务器建立连接并转发数据。

这样,当存在一个客户端和服务端的通信时,网关有可能需要同时建立两个连接,占用两个fd。这对网关的数据处理能力提出了较高的要求。

在调试中出现的现象是,当客户端以较多的并发的速率向网关建立连接时,网关会因为已经打开的fd过多而拒绝连接,导致来自客户端的连接建立失败。

本文就对此现象进行了简略分析,同时复习一下linux下的文件描述符。

系统中fd的限制

linux系统中通常会对每个进程所能打开的文件数据有一个限制,当进程中已打开的文件描述符超过这个限制时,open()等获取文件描述符的系统调用都会返回失败。

linux下最大文件描述符的限制有两个方面,一个是用户级的限制,另外一个则是系统级限制。

  • 用户级限制:ulimit命令看到的是用户级的最大文件描述符限制,也就是说每一个用户登录后执行的程序占用文件描述符的总数不能超过这个限制
  • 系统级限制:sysctl命令和proc文件系统中查看到的数值是一样的,这属于系统级限制,它是限制所有用户打开文件描述符的总和

查看限制数量

  • 查看用户级限制:ulimit -n
-> % ulimit -n
1024
  • 系统级限制:
    • sysctl -a
    • cat /proc/sys/fs/file-max
-> % sysctl -a | grep file-max
sysctl: fs.file-max = 100262

-> % cat /proc/sys/fs/file-max 
100262

修改限制数量

  • 修改用户级限制
    • 临时修改,只对当前shell有效:ulimit -HSn 65536
    • 永久修改:编辑/etc/security/limits.conf
-> % ulimit -SHn 2048
yao@yao-virtual-machine [10时49分18秒] [~/work/util] 
-> % ulimit -n
2048

vi /etc/security/limits.conf
* hard nofile 65536
* soft nofile 65536
  • 修改系统级限制
    通过sysctl命令修改/etc/sysctl.conf文件:sysctl -w fs.file-max=2048,完成后执行sysctl -p即可

文件描述符简述

简述

在Linux通用I/O模型中,I/O操作系列函数(系统调用)都是围绕一个叫做文件描述符的整数展开。

I/O操作系统调用都以文件描述符(一个非负整数),指代打开的文件。每个进程都有一个打开文件表,可以理解成一个数组,文件描述符可以理解成数组的下标。

相关I/O操作系统调用以文件描述符为参数,便可以通过数组访问定位到指定的文件对象,进而进行I/O操作。

当某个程序打开文件时,操作系统返回相应的文件描述符,程序为了处理该文件必须引用此描述符。所谓的文件描述符是一个低级的正整数。最前面的三个文件描述符(0,1,2)分别与标准输入(stdin),标准输出(stdout)和标准错误(stderr)对应,如下表。

文件描述符 用途 POSIX名称 stdio流
0 标准输入 STDIN_FILENO stdin
1 标准输出 STDOUT_FILENO stdout
2 标准出错 STDERR_FILENO stderr

正常情况下,程序在开始运行之前,由shell准备好这3个文件描述符。更准确的说法是,程序继承了shell文件描述符的副本,一般是指向shell所在的终端。当然了,可以通过在shell中对输入/输出进行重定向或者在程序启动后关闭并重新打开文件描述符,修改文件描述符指向。

在linux系统中,内核维护了三个数据结构,分别是进程级文件描述符表、系统级打开文件表和文件系统i-node表。

文件描述符表

内核为每个进程维护一个文件描述符表,该表每一条目都记录了单个文件描述符的相关信息,包括:

  • 控制标志(flags),目前内核仅定义了一个,即close-on-exec
  • 打开文件描述体指针

打开文件表

内核对所有打开的文件维护一个系统级别的打开文件描述表(open file description table),简称打开文件表。表中条目称为打开文件描述体(open file description),存储了与一个打开文件相关的全部信息,包括:

  • 文件偏移量(file offset),调用read()和write()更新,调用lseek()直接修改
  • 访问模式,由open()调用设置,例如:只读、只写或读写等
  • i-node对象指针

i-node表

每个文件系统会为存储于其上的所有文件(包括目录)维护一个i-node表,单个i-node包含以下信息:

  • 文件类型(file type),可以是常规文件、目录、套接字或FIFO
  • 访问权限
  • 文件锁列表(file locks)
  • 文件大小

i-node存储在磁盘设备上,内核在内存中维护了一个副本,这里的i-node表为后者。副本除了原有信息,还包括:引用计数(从打开文件描述体)、所在设备号以及一些临时属性,例如文件锁。

复制与关闭

  1. 文件描述符的复制和重定向非常简单,使用dup()系统调用即可完成。在shell中,使用>即可进行重定向。

流程如下:

  • 打开目标文件,返回文件描述符n;
  • 关闭文件描述符1;
  • 调用dup将文件描述符n复制到1;
  • 关闭文件描述符n;
  1. 在程序中使用fork()创建子进程时,父进程中已经打开的fd也会自动在子进程中打开。子进程可以直接对这些文件进行操作。

此时,需要分别在子进程和父进程中关闭fd。一般父进程创建子进程后,父进程会直接关闭掉fd,子进程处理完成后再关闭fd。

  1. 使用unix域套接字也可以进行文件描述符的传递,但从一个进程传递到另一个进程后,fd可能会发生变化。

注意使用完毕后,分别关闭fd。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容

  • 知足, 是对世间万事最好的谅解, 也是对世间万事最坏的无奈。
    先木先生的话阅读 435评论 0 1
  • > 拼自己,不「拼爹」 挫折,孕育着更好的礼物。毕业时,我之前几个月的实习已经结出硕果。我在中国国际广播电台华侨部...
    医路洁行阅读 502评论 0 0
  • 就在刚才 3点多 做了一个美梦 我梦到 我去找你 工作的机器突然出现故障 于是你要去外面 我玩笑似的抓住你的手 没...
    viy阅读 244评论 0 0