基本概念
文件描述符fd
Linux 系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符,文件描述符就是内核为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,所有执行I/O操作的系统调用都会通过文件描述符。
常见文件类型
-
普通文件:包含任意数据
-
目录:包含一组链接(link)的文件
-
套接字(socket):用来与另一个进程进行跨网络通信的文件
-
命名通道
-
符号链接
-
支付和块设备
linux抽象了一组标准接口,叫unix I/O,使得所有的输入和输出都能以一种统一的方式来执行;
-
打开文件,应用程序通过内核创建,以宣告想要访问的I/O设备;返回一个小的非负整数,内核记录有关这个打开文件的所有信息,应用程序只需记录这个描述符。
-
每个进程都有三个打开的文件
-
标注输入(描述符为0)
-
标准输出 (描述符为1)
-
标准错误(描述符为2)
-
这也是为什么nohup command 2>&1 &
-
每个打开的文件内核保持一个文件位置k,初始为0
-
读写文件:从文件复制n个字节到内存,从当前的文件位置k开始增加n,当k>=文件的大小时,会触发一个end-of-file(EOF)的条件;
-
关闭文件:内核释放文件打开时创建的数据结构,并恢复到可用的描述符池中;
-
从这里可以看出文件描述符是从小到大创建;
-
文件描述符是可以重复利用的
套接字socket
套接字允许用于链接到网络,套接字与邮筒和墙壁上的电话插座是类似的,看下示意图(现代操作系统里的)
-
套接字可以被动态的创建和销毁
-
创建一个套接字成功后会返回一个文件描述符
-
创建连接、读数据、写数据、解除连接需要用到文件描述符
-
套接字必须有一个地址与它绑定
-
源计算机和目标计算机都建立成功后,则两个计算机之间可以建立一个链接;
-
网路是水管,套接字就是水管的口子,连接就是那两个口子相通;
基于套接字接口的额网络应用
-
connect 客户端通过此函数和服务器建立连接;
-
bind 服务端绑定一个ip和端口
-
listen 用于监听客户端的请求(将套接字转成监听套接字)
-
accept 等待客户端的连接请求
在redis的源码中,
# 通过acceptTcpHandler中anet.c文件里的anetGenericAccept获取socket监听的fd
fd = accept(s,sa,len);
然后通过createClient将新创建的fd绑定到了client上
并在这个fd上绑定了一个回调函数readQueryFromClient用于处理AE_READABLE事件
epoll和kqueue通过aeApiAddEvent 将这个fd注册到事件处理器的fd上,并且会标注事件类型
在readQueryFromClient中会通过
read(fd, c->querybuf+qblen, readlen);
从网络缓冲区读取数据
在writeToClient中通过
nwritten = write(fd,c->buf+c->sentlen,c->bufpos-c->sentlen);
写入网络缓冲区
文件的三张表
内核用三个相关的数据结构来表示打开的文件:
-
描述符表(descriptor table)
-
每个进程独立
-
用进程打开的文件描述符来做索引
-
文件表(file table)
-
所有进程共享这张表
-
打开文件在在内存中的表示
-
通过open调用时创建,支持read、write、sendfile、lock等系统调用
-
包括当前文件位置、引用计数(打开引用计数会+1)、指向i-node的指针
-
inode表(index-node table)
-
所有进程共享这张表
-
表示某个确切的文件(目录和块也是文件)
系统调用 | 描述 |
---|---|
fd=creat(name,mode) | 创建文件的一种方法 |
fd=open(file,how,...) | 打开文件读、写或者读写 |
s=close(fd) | 关闭一个已打开的文件 |
n=read(fd,buffer,nbytes) | 从文件读取一些数据到缓冲区 |
n=write(fd,buffer,nbytes) | 把数据从缓冲区写入到文件 |
position=lseek(fd,offset,whence) | 移动文件指针 |
s=stat(name,&buf) | 获取一个文件的状态信息 |
s=fstat(fd,&buf) | 获取一个文件的状态信息 |
s=pipe(&fd[0]) | 创建一个管道 |
s=fcntl(fd,cmd,...) | 文件加锁及其他操作 |
当然这里还会做很多的缓存优化,这里不做详解。
参考:《现代操作系统》10.6 linux文件系统 《深入理解计算机系统》 第10章 系统级I/O