搞懂Linux下的几种文件类型
在Linux系统下,有七类文件类型:
- 普通文件(-)
- 目录(d)
- 软链接(字符链接L)
- 套接字文件(S)
- 字符设备(S)
- 块设备(B)
- 管道文件(命名管道P)
普通文件、目录、软链接无需多解释。
管道文件
管道分为匿名管道和命名管道。管道都是一端写入、另一端读取,它们是单方向数据传输的,它们的数据都是直接在内存中传输的,管道是进程间通信的一种方式,例如父进程写,子进程读。
在shell中匿名管道就是一个管道符号"|",例如ls | grep xxx,其中ls对应的进程是这个独立进程组中的父进程,grep对应的进程是子进程,父进程写子进程读。
在编程语言中,匿名管道是通过创建两个文件句柄或文件描述符(例如A、B)来实现的,一个文件句柄用于写数据(例如A写入端,数据写入A将自动推入B中),另一个文件句柄用于读数据(即B)。
对于命名管道,即有名称的管道,命名管道将文件保留在文件系统中,它也称为FIFO,也就是first in first out。虽然命名管道文件保留在文件系统中,但是这个文件只是使用命名管道的一个入口,在使用命名管道传输数据的时候,仍然是在内存中进行的,也就是说并不会因为保留在文件系统上命名管道的效率就低了。
在shell中,可以使用mknod命令或mkfifo命令创建命名管道,在写某些特殊需求的shell脚本时,命名管道非常有用。实际上,在Bash 4之后就支持协程(使用coproc命令)的功能了(ksh和zsh老早就支持协程),但是协程的需求都能通过命名管道来实现。
一般的管道都是单向通信的,无法实现双向通信的功能,也就是只能一边写一边读,不能两边都能读、写。如果要实现双向通信,可以创建两根管道(这样就有4个文件句柄,两个读端,两个写端),或者使用更方便的套接字。
套接字(Socket)
套接字用来实现两端通信,正如上面分析的,可以实现双向管道的进程间通信功能。不仅如此,套接字还能通过网络实现跨主机的进程间通信功能。
套接字需要成对才有意义,也就是分为两端,每一端都有用于读、写的文件描述符(或文件句柄),相当于两根双向通信的管道。
套接字根据协议族的方式分为两大类:网络套接字(AF_INET类型,根据ipv4和ipv6分为inet4和inet6)和Unix Domain套接字(AF_UNIX类型)。当然,从协议族往下,套接字可细分为很多种类型,例如INET套接字可以分为TCP套接字、UDP套接字、链路层套接字、Raw套接字等等。其中网络套接字是网络编程的基础和核心。
Unix Domain套接字
对于单机的进程间通信,使用Unix Domain套接字比Inet套接字更好,因为Unix Domain套接字没有网络通信组件,也就是少了很多网络功能,它更加轻量级。实际上,某些语言在某些操作系统平台上实现的管道功能就是通过Unix Domain来实现的,可想而知其高效率。
Unix Domain套接字有两个文件句柄(例如A、B),这两个文件句柄都是同时可读、可写的句柄。进程1向A写入数据,将自动推送到B上,进程2可从B上读取从A写入的数据,同理进程2向B中写入数据将自动推送到A上,进程1可从A上读取从B写入的数据。如下:
进程1 进程2
------------------------
A -----------> B
B -----------> A
在编程语言中,创建Unix Domain Socket自然有对应的函数轻松创建(可man socketpair)。对于bash shell,可以通过nc命令(NetCat)来创建,或者干脆使用两个命名管道来实现对应的功能。如有需要,可自行了解如何在bash shell中使用Unix Domain套接字。
网络套接字
对于跨网络的进程间通信,需要使用网络套接字。每个网络套接字都由5部分组成,它们称为套接字的5元组。格式如下:
{protocol, src_addr, src_port, dest_addr, dest_port}
即协议、源地址、源端口、目标地址、目标端口。
每端套接字在内核空间都有两个buffer(即一对socket有4个buffer),每一端都有recv buffer和send buffer。进程1向自己的套接字的send buffer写入数据,将发送到对端的recv buffer中,然后对端的进程2就可以从recv buffer中读取数据,反之亦然。
但是在真正可以读、写网络套接字之前,网路套接字还需要一些设置。服务端套接字创建(socket()函数,创建后就会有一个文件句柄或文件描述符供读、写操作)后,还要绑定地址(通过bind()函数)和监听端口(通过listen()函数),客户端则只需要创建套接字后,直接使用connect()函数向服务端套接字发起连接请求即可。
对于TCP套接字,客户端发起连接请求即表示要和服务端进行三次握手(内核完成,和用户空间进程无关)。将这三次握手的每一次进行细分,第一次客户端发送SYN请求,服务端接收到SYN后,内核将这个连接放进syn queue中并设置状态为syn-recv,然后发送ack+syn给客户端,当接收到客户端回复ack后,内核将连接从syn queue移到established queue(或accept queue)中并将连接的状态标记为established。最后等待用户空间的进程发起accept()系统调用让内核将其从accept queue中移除。被accept()后的连接表示已经建立好的连接,可以真正实现两端进程间的数据传输。
更多关于TCP套接字的原理,参见我的另一篇文章:不可不知的socket和TCP连接过程。
块设备和字符设备
块设备是硬件设备,通过随机(不一定是顺序)访问固定大小的数据块(chunk)来区分。固定大小的chunk称为块(block)。最常见的块设备是硬盘,但也存在许多其他块设备,如软盘驱动器、蓝光阅读器和闪存。注意,这些都是挂载文件系统的设备,文件系统就像是块设备的通用语言。
字符设备通过连续的流数据访问,一个字节接着一个字节。典型的字符设备是终端(终端分多种,由物理的也有虚拟的)和键盘。
区分块设备和字符设备最简单的方法是看数据访问的方式。能随机访问获取数据的是块设备,必须按字节顺序访问的是字符设备。
如果可以这里读一点数据,那里读一点数据,最后串成一整段连续的数据,那么这个就是块设备,就像硬盘上的数据是不连续的,有可能需要通过随机访问的方式获取一段数据。比如磁盘上一个稍大一点的文件,可能前10k数据是连续的数据块或在连续的扇区内,之后的10k数据在离它很远甚至在不同的柱面上。
如果一段数据中的每个字节都跟访问时的字节顺序是一样的,即字节先后顺序从访问获取时到最后处理数据的过程中都是完全一致的,那么这个就是字符设备。换句话说,字符设备可以看作是流设备。就像键盘输入数据一样,连续敲两个字键,这两个键对应的字节数据在被接收的时候一定是先敲的在前面,后敲的在后面。同理终端设备也是以一样的,程序将数据输出到终端时,程序先输出字母a再输出数字3,那么显示在终端上时一定是a在前,3在后。
搞懂Linux下的几种文件类型的更多相关文章
- Linux 下的7种文件类型
普通文件类型 (-)Linux中最多的一种文件类型, 包括 纯文本文件(ASCII):二进制文件(binary):数据格式的文件(data);各种压缩文件.第一个属性为 [-] ,这些文件一般是用一些 ...
- Linux 文件系统 -- 简述几种文件类型
Linux 中一切皆为文件,文件类型也有多种,使用 ls -l 命令可以查看文件的属性,所显示结果的第一列的第一个字符用来表明该文件的文件类型,如下: 1.普通文件 使用 ls -l 命令后,第一列第 ...
- Linux下设置svn过滤文件类型
1)修改客户端. 1.修改客户端 1)编辑文件家目录下自己账户下的.subversion/config文件 vim ~/.subversion/config 2)找到包含[miscellany]的一行 ...
- 【Linux】七种文件类型
Linux中的七种文件类型 d 目录文件. l 符号链接(指向另一个文件). s 套接字文件. b 块设备文件,二进制文件. c 字符设备文件. p 命名管道文件. - 普通文件
- linux文件属性详解及文件类型
一 drwxr-xr-x的意思解释: ls -al 得到如下列表: drwxr-xr-x oracle dba May : oralog1 drwxr-x--- root root May : ro ...
- Linux下查看alert日志文件的两种方法
--linux下查看alert日志文件的两种方法: --方法1: SQL> show parameter background_dump_dest; NAME TYPE VALUE ------ ...
- Linux 下的五种 IO 模型
概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的 ...
- linux下怎样批量更改文件后缀名
今天又有同学问linux下怎样批量更改文件后缀名,这个问题被别人问到三次了,所以这里给出几个解决方法 一.rename解决 1. Ubuntu系统下 rename 's//.c//.h/' ./* ...
- Linux下的5种I/O模型(转)
Linux下的五种I/O模型: l 阻塞I/O l 非阻塞I/O l I/O复用(select.poll.epoll) l 信号驱动I/ ...
随机推荐
- Flume+Kafka+Storm+Hbase+HDSF+Poi整合
Flume+Kafka+Storm+Hbase+HDSF+Poi整合 需求: 针对一个网站,我们需要根据用户的行为记录日志信息,分析对我们有用的数据. 举例:这个网站www.hongten.com(当 ...
- 怎么过滤
replace(str, " ", ""); 就是这么简单
- windows下 mysql 5.6.40 卸载 安装 修改密码
最近执行另一个mysql版本导出的sql脚本,出现问题!出于一些原因,把之前的mysql5.5卸载,由于卸载不干净出现了一些问题.特此总结方法! 参考链接: https://blog.csdn.net ...
- js计算指定日期的下一年的日期
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 微信小程序开发资料
微信开放平台:主要面向App开发者.通常是拥有成熟的应用程序后,通过开放平台将内容分享到朋友圈或发送给某个微信好友/群.例如QQ音乐分享,美图秀秀修改过的照片直接发朋友圈或聊天. 微信公众平台:强 ...
- 深入理解Spring Redis的使用 (九)、通过Redis 实现 分布式锁 的 BUG,以及和数据库加锁的性能测试
在多节点的项目中,经常要涉及到某些方法加锁的控制.而这个时候,简单易用的synchronized已经不能满足多节点的部署结构. 之前在项目中,用的比较多的是数据库的更新锁:for udpate.但是这 ...
- 二叉查找树(BST)的实现
一.二叉树介绍 二叉查找树(Binary Search Tree,BST),又称二叉排序树,也称二叉搜索树,它或者是一颗空树,或者具有如下性质的树:若它的左子树不为空,则左子树上所有节点的值都小于根节 ...
- [Swift]LeetCode241. 为运算表达式设计优先级 | Different Ways to Add Parentheses
Given a string of numbers and operators, return all possible results from computing all the differen ...
- [Swift]LeetCode677. 键值映射 | Map Sum Pairs
Implement a MapSum class with insert, and sum methods. For the method insert, you'll be given a pair ...
- Python档案袋(文件系列操作 )
文件读写基础 简单的读文件: # r 表示只能读 #打开文件,得到文件光标对象,文件不存在则报错 f=open("ww.txt","r",encoding=&q ...