手把手写C++服务器(25):万物皆可文件之socket fd

Posted 沉迷单车的追风少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手写C++服务器(25):万物皆可文件之socket fd相关的知识,希望对你有一定的参考价值。

 本系列文章导航: 手把手写C++服务器(0):专栏文章-汇总导航【更新中】 

前言:大家一定听说过在Linux当中,万物皆是文件,任何客观的存在都是以文件形式呈现。前面讲socket编程的时候(手把手写C++服务器(21):Linux socket网络编程入门基础手把手写C++服务器(22):Linux socket网络编程进阶第一弹)可以看出,sockfd伴随socket的“生老病死”,这一讲就从Linux文件描述符开始讲起,详细聊一聊socket fd。

目录

万物皆可文件的Linux

服务器最宝贵的资源之一——文件描述符

文件描述符

最大文件描述符限制

系统建立三个表维护文件描述符

 查看进程占用的文件描述符限制

网络文件描述符

什么是inode?

查看当tcp连接状态

sockfs 文件系统

创建socket()

绑定bind()

监听listen()

epoll池化管理socket

参考


万物皆可文件的Linux

在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件、目录文件、链接文件和设备文件。在操作这些所谓的文件的时候,我们每操作一次就找一次名字,这会耗费大量的时间和效率。所以Linux中规定每一个文件对应一个索引,这样要操作文件的时候,我们直接找到索引就可以对其进行操作了。

服务器最宝贵的资源之一——文件描述符

文件描述符

文件描述符(file descriptor)就是内核为了高效管理这些已经被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符来实现

文件描述符是服务器程序最宝贵的资源之一,几乎所有系统调用都是和文件描述符打交道,但是系统分配给应用程序的文件描述符数量是有限的。同时还规定系统刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。这意味着如果此时去打开一个新的文件,它的文件描述符会是3,再打开一个文件文件描述符就是4,以此类推。

每个进程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。 当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符

最大文件描述符限制

Linux对应用程序能打开的最大文件描述符数量总共有两个层次的限制:用户级限制和系统级限制

  • 用户级限制:目标用户运行的所有进程总共能打开的文件描述符数。
  • 系统级限制:所有用户总共能打开的文件描述符数。

查看用户级文件文件描述符限制:

ulimit -n
1024

显示目前系统资源限定:

ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 514162
max locked memory       (kbytes, -l) 16384
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

系统建立三个表维护文件描述符

  • 进程级的文件描述符表

  • 系统级的文件描述符表

  • 文件系统的i-node表

 查看进程占用的文件描述符限制

不熟悉这些Linux命令的可以去看我的系列文章,虽然还没有发出哈哈哈

ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  18384  3128 ?        Ss   Aug04   0:49 /bin/bash -c service ssh start; while true;do sleep 10;done
root        14  0.0  0.0  72308  4088 ?        Ss   Aug04   0:00 /usr/sbin/sshd
root     39608  0.0  0.0  30564  3208 ?        Ss   Aug14   0:28 SCREEN -S linear
root     39609  0.0  0.0  20452  4072 pts/2    Ss+  Aug14   0:00 /bin/bash
root     50635  0.0  0.0 107992  7216 ?        Rs   07:18   0:00 sshd: root@pts/0
root     50646  0.0  0.0  20436  4092 pts/0    Ss   07:18   0:00 -bash
root     50825  0.0  0.0   4548   796 ?        S    07:42   0:00 sleep 10
root     50828  0.0  0.0  38380  3572 pts/0    R+   07:42   0:00 ps -aux
cat /proc/39608/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        unlimited            unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             unlimited            unlimited            processes
Max open files            1024                 1048576              files
Max locked memory         16777216             16777216             bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       514162               514162               signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

在 Max open files 那一行,可以看到当前设置中最大文件描述符的数量为1024

网络文件描述符

什么是inode?

阮一峰说的非常精彩了:http://www.ruanyifeng.com/blog/2011/12/inode.html

inode 是 vfs 抽象的适配所有文件系统的结构体,但分配其实是有下层具体文件系统分配出来的,以 ext4 文件系统来说,使用 ext4_alloc_inode 函数分配出 ext4_inode_info 这个大结构体,然后返回的是 inode 的地址而已。

查看当tcp连接状态

可以获取当前tcp连接的innode信息

cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode

   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 14111686 1 0000000000000000 100 0 0 10 0

   1: 040011AC:0016 1602260A:EBA5 01 00000024:00000000 01:0000001B 00000000     0        0 99084810 4 0000000000000000 28 4 31 10 -1

sockfs 文件系统

sockfs 文件系统,普通用户看不见,这是只由内核管理的文件系统,位于 vfs 之下,为了封装 socket 对上的文件语义。

// net/socket.c
static int __init sock_init(void)
{
    // 注册 sockfs 文件系统
    err = register_filesystem(&sock_fs_type);
    // 内核挂载
    sock_mnt = kern_mount(&sock_fs_type);
}

创建socket()

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type,int protocol);

socket( ) 返回的是非负整数的 fd,与 struct file 对应,而 struct file 则与具体的 struct socket 关联,从而实现一切皆文件的封装的一部分(另一部分 inode 的创建处理在 sock_alloc 的函数里体现);

绑定bind()

#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr*my_addr,socklen_t addrlen);
  1. 先通过 fd 找到对应的 struct socket 结构体;

  2. 然后把 address 和 socket 绑定对应起来(调用 sock->ops->bind 函数);

监听listen()

#include<sys/socket.h>
int listen(int sockfd,int backlog);
  1. 通过 fd 找到 struct socket 结构体;

  2. 调用 sock->ops->listen 函数(对应 inet_listen );

epoll池化管理socket

epoll 池能管理 socketfd,因为 socket fd 实现 poll 接口。具体的管理方法会在本系列后面的文章中详细讲解。

参考

以上是关于手把手写C++服务器(25):万物皆可文件之socket fd的主要内容,如果未能解决你的问题,请参考以下文章

手把手写C++服务器(27):五大文件描述符零拷贝控制总结

手把手写C++服务器(31):服务器性能提升关键——IO复用技术两万字长文

手把手写C++服务器(31):服务器性能提升关键——IO复用技术两万字长文

万物皆可 GAN生成对抗网络生成手写数字 Part 1

万物皆可 GAN生成对抗网络生成手写数字 Part 2

手把手写C++服务器(32):三大事件之信号详解