Linux下文件输入/输出端口的试炼分析

发布时间:2021-10-27 10:30:55 作者:小新
来源:亿速云 阅读:134

这篇文章将为大家详细讲解有关Linux下文件输入/输出端口的试炼分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

文件描述符(File Descriptor)

a small, nonnegative integer for use in subsequent system calls (read(2), write(2), lseek(2), fcntl(2), etc.) ($man 2 open). 一个程序开始运行时一般会有3个已经打开的文件描述符:

fd原理

Linux下文件输入/输出端口的试炼分析

文件描述符标志(File Descriptor Flag)

当下的系统只有一个文件描述符标志close-on-exec,仅仅是一个标志,当进程fork一个子进程的时候,在子进程中调用了exec函数时就用到了该标志。意义是执行exec前是否要关闭这个文件描述符。

Note:虽然新版本支持在open时设置CLOEXEC,但是在编译的时候还是会提示错误 - error: ‘O_CLOEXEC’ undeclared (first use in this function)。这个功能需要设置宏(_GNU_SOURCE)打开。

#define _GNU_SOURCE //在源代码中加入
-D_GNU_SOURCE //在编译参数中加入

文件状态标志(File Status Flag)

File status flags 用来表示打开文件的属性,file status flag可以通过duplicate一个文件描述符来共享同一个打开的文件的状态,而file descrptor flag则不行

open()

//给定一个文件路径名,按照相应的选项打开文件,就是将一个fd和文件连接到一起,成功返回文件描述符,失败返回-1设errno  #include<fcntl.h>  int open(const char *pathname, int flags)  int open(const char *pathname, int flags, mode_t mode)  //不是函数重载,C中没有重载, 是可变长参数列表 //pathname:文件或设备路径 //flags :file status flags=Access mode+Open-time flags+Operating Modes、 /*Access Mode(必选一个): O_RDONLY:0 O_WRONLY:1 O_RDWR:2 */ /*Open-time Flags(Bitwise Or): O_CLOEXEC   :为新打开的文件描述符使能close-on-exec。可以避免程序再用fcntl()的F_SETFD来设置FD_CLOEXEC O_CREAT     :如果文件不存在就创建文件,并返回它的文件描述符,如果文件存在就忽略这个选项,必须在保护模式下使用,eg:0664 O_DIRECTORY :如果opendir()在一个FIFO或tape中调用的话,这个选项可以避免denial-of-service问题,  如果路径指向的不是一个目录,就会打开失败。 O_EXCL      :确保open()能够穿件一个文件,如果文件已经存在,则会导致打开失败,总是和O_CREAT一同使用。 O_NOCTTY    :如果路径指向一个终端设备,那么这个设备不会成为这个进程的控制终端,即使这个进程没有一个控制终端 O_NOFOLLOW  :如果路径是一个符号链接,就打开它链接的文件//If pathname is a symbolic link, then the open fails. O_TMPFILE   :创建一个无名的临时文件,文件系统中会创建一个无名的inode,当***一个文件描述符被关闭的时候,所有写入这个文件的内容都会丢失,除非在此之前给了它一个名字 O_TRUNC     :清空文件 O_TTY_INIT *//*Operating Modes(Bitwise Or) O_APPEND    :以追加的方式打开文件, 默认写入结尾,在当下的Unix/Linux系统中,这个选项已经被定义为一个原子操作   O_ASYNC     :使能signal-driven I/O O_DIRECT    :试图最小化来自I/O和这个文件的cache effect//Try to minimize cache effects of the I/O to and from this  file. O_DSYNC     :每次写操作都会等待I/O操作的完成,但如果文件属性的更新不影响读取刚刚写入的数据的话,就不会等待文件属性的更新    。 O_LARGEFILE :允许打开一个大小超过off_t(但没超过off64_t)表示范围的文件 O_NOATIME   :不更改文件的st_time(last access time) O_NONBLOCK /O_NDELAY :如果可能的话,用nonblock模式打开文件 O_SYNC      :每次写操作都会等待I/O操作的完成,包括write()引起的文件属性的更新。 O_PATH      :获得一个能表示文件在文件系统中位置的文件描述符
#include<fcntl.h>  #include<stdlib.h>  int fd=open("b.txt",O_RDWR|O_CREAT|O_EXCL,0664); if(-1==fd)     perror("open"),exit(-1);

FA:猜想有以下模型:用一串某一位是1其余全是0的字符串表示一个选项, 选项们作 “按位与”就可得到0/1字符串, 表示整个flags的状态, Note: 低三位表示Access Mode

creat()

等价于以O_WRONLY |O_TRUNC|O_CREAT的flag调用open()

#include<fcntl.h>  int creat(const char *pathname, mode_t mode);

dup()、dup2()、dup3()

/复制一个文件描述符的指向,新的文件描述符的flags和原来的一样,成功返回new_file_descriptor, 失败返回-1并设errno  #include <unistd.h>  int dup(int oldfd);           //使用未被占用的最小的文件描述符编号作为新的文件描述符  int dup2(int oldfd, int newfd);
#include <fcntl.h>       #include <unistd.h>  int dup3(int oldfd, int newfd, int flags);
#include<unistd.h>  #include<stdlib.h>  int res=dup2(fd,fd2); if(-1==res){         perror("dup2"),exit(-1); }

Linux下文件输入/输出端口的试炼分析

read()

//从fd对应的文件中读count个byte的数据到以buf开头的缓冲区中,成功返回成功读取到的byte的数目,失败返回-1设errno  #include <unistd.h>  ssize_t read(int fd, void *buf, size_t count);
#include <unistd.h>  #include<stdlib.h>  int res=read(fd,buf,6); if(-1==fd)     perror("read"),exit(-1);

write()

//从buf指向的缓冲区中读取count个byte的数据写入到fd对应的文件中,成功返回成功写入的byte数目,文件的位置指针会向前移动这个数目,失败返回-1设errno  #include <unistd.h>  ssize_t write(int fd, const void *buf, size_t count);//不需要对buf操作, 所以有const, VS read()没有const
#include <unistd.h>  #include<stdlib.h>  int res=write(fd,"hello",sizeof("hello")); if(-1==res)     perror("write"),exit(-1);

Note: 上例中即使只有一个字符&rsquo;A&rsquo;,也要写”A”,因为”A”才是地址,&rsquo;A&rsquo;只是个int

lseek()

l 表示long int, 历史原因

//根据移动基准whence和移动距离offset对文件的位置指针进行重新定位,返回移动后的位置指针与文件开头的距离,失败返回-1设errno  #include <unistd.h>  #include <sys/types.h>  off_t lseek(int fd, off_t offset, int whence); /*whence: SEEK_SET:以文件开头为基准进行偏移,0一般不能向前偏 SEEK_CUR:以当前位置指针的位置为基准进行偏移,1向前向后均可 SEEK_END:以文件的结尾为基准进行偏移,2向前向后均可向后形成”文件空洞”
#include<unistd.h>  #include<stdlib>  int len=lseek(fd,-3,SEEK_SET); if(-1==len){         perror("lseek"),exit(-1); }

fcntl()

//对fd进行各种操作,成功返回0,失败返回-1设errno #include <unistd.h> #include <fcntl.h>  int fcntl(int fd, int cmd, ... );       //...表示可变长参数 /*cmd: Adversory record locking: F_SETLK(struct flock*)  //设建议锁 F_SETLKW(struct flock*) //设建议锁,如果文件上有冲突的锁,且在等待的时候捕获了一个信号,则调用被打断并在信号捕获之后立即返回一个错误,如果等待期间没有信号,则一直等待  F_GETLK(struct flock*)  //尝试放锁,如果能放锁,则不会放锁,而是返回一个含有F_UNLCK而其他不变的l_type类型,如果不能放锁,那么fcntl()会将新类型的锁加在文件上,并把当前PID留在锁上 Duplicating a file descriptor: F_DUPFD (int)       //找到>=arg的最小的可以使用的文件描述符,并把这个文件描述符用作fd的一个副本 F_DUPFD_CLOEXEC(int)//和F_DUPFD一样,除了会在新的文件描述符上设置close-on-execF_GETFD (void)      //读取fd的flag,忽略arg的值 F_SETFD (int)       //将fd的flags设置成arg的值. F_GETFL (void)      //读取fd的Access Mode和其他的file status flags; 忽略arg F_SETFL (long)      //设置file status flags为arg F_GETOWN(void)      //返回fd上接受SIGIO和SIGURG的PID或进程组ID F_SETOWN(int)       //设置fd上接受SIGIO和SIGURG的PID或进程组ID为arg F_GETOWN_EX(struct f_owner_ex*) //返回当前文件被之前的F_SETOWN_EX操作定义的文件描述符R F_SETOWN_EX(struct f_owner_ex*) //和F_SETOWN类似,允许调用程序将fd的I/O信号处理权限直接交给一个线程,进程或进程组 F_GETSIG(void)      //当文件的输入输出可用时返回一个信号 F_SETSIG(int)       //当文件的输入输出可用时发送arg指定的信号 */  /*&hellip;:     可选参素,是否需要得看cmd,如果是加锁,这里应是struct flock* struct flock {     short l_type;   //%d Type of lock: F_RDLCK(读锁), F_WRLCK(写锁), F_UNLCK(解锁)     short l_whence; //%d How to interpret l_start, 加锁的位置参考标准:SEEK_SET, SEEK_CUR, SEEK_END     off_t l_start;  //%ld Starting offset for lock,     加锁的起始位置     off_t l_len;    //%ld Number of bytes to lock , 锁定的字节数     pid_t l_pid;    // PID of process blocking our lock, (F_GETLK only)加锁的进程号,,默认给-1}; */

建议锁(Adversory Lock)

限制加锁,但不限制读写, 所以只对加锁成功才读写的程序有效,用来解决不同的进程 同时对同一个文件的同一个位置 “写”导致的冲突问题

读锁是一把共享锁(S锁):共享锁+共享锁+共享锁+共享锁+共享锁+共享锁

写锁是一把排他锁(X锁):永远孤苦伶仃

释放锁的方法(逐级提高):

Q:为什么加了写锁还能gedit或vim写???

A:可以写, 锁只可以控制能否加锁成功, 不能控制对文件的读写, 所以叫”建议”锁, 我加了锁就是不想让你写, 你非要写我也没办法. vim/gedit不通过能否加锁成功来决定是否读写, 所以可以直接上

Q: So如何实现文件锁控制文件的读写操作????

A:可以在读操作前尝试加读锁, 写操作前尝试加写锁, 根据能否加锁成功决定能否进行读写操作

int fd=open("./a.txt",O_RDWR);                  //得到fd  if(-1==fd)     perror("open"),exit(-1);struct flock lock={F_RDLCK,SEEK_SET,2,5,-1};    //设置锁   //此处从第3个byte开始(包含第三)锁5byte  int res=fcntl(fd,F_SETLK,&lock);                //给fd加锁  if(-1==res)     perror("fcntl"),exit(-1);

ioct1()

这个函数可以实现其他文件操作函数所没有的功能,大多数情况下都用在设备驱动程序里,每个设备驱动程序可以定义自己专用的一组ioctl命令,系统则为不同种类的设备提供通用的ioctl命令

//操作特殊文件的设备参数,成功返回0,失败返回-1设errno  #include <sys/ioctl.h>  int ioctl(int d, int request, ...); //d:an open file descriptor.//request: a device-dependent  request  code

close()

//关闭fd,这样这个fd就可以重新用于连接其他文件,成功返回0,失败返回-1设errno  #include <unistd.h>  int close(int fd);
#include <unistd.h> #include<stdlib.h>  int res=close(fd); if(-1==res)         perror("close"),exit(-1);

关于“Linux下文件输入/输出端口的试炼分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

推荐阅读:
  1. 我的linux学习之旅: (3)编译安装php5.4
  2. Linux编辑器vim命令解释

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux

上一篇:Linux下file怎么用

下一篇:Mysql数据分组排名实现的示例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》