跨平台C++服务器程序开发 (3)Linux文件描述符
来源:互联网 发布:手机端如何查看源码 编辑:程序博客网 时间:2024/06/06 02:59
Linux文件描述符
在Linux系统中几乎所有可读写的对象都可视为文件,比如标准输入输出、磁盘文件、套接字、管道等,都可以用read
函数读取数据,用write
函数写入数据。 这一点相对于Windows系统来说更加统一,在Windows系统中上面列举的每个对象都有其专门的一组函数读写。
下面分别描述这几种文件对象。
标准输入输出
在C语言中,printf
向控制台窗口输出信息,scanf
从控制台窗口输入信息,并且内置了stdin、stdout、stderr
3个文件描述符,分别对应数字0、1、2。
#define stdin (&__iob_func()[0])#define stdout (&__iob_func()[1])#define stderr (&__iob_func()[2])
在C++语言中,cout
向控制台输出,cin
从控制台输入,cerr
错误输出。
在Linux系统头文件unistd.h
定义了类似的3个宏。
STDERR_FILENO File number of stderr; 2. STDIN_FILENO File number of stdin; 0. STDOUT_FILENO File number of stdout; 1.
每当我们在shell里运行一个新程序时,shell进程都会为新程序打开这3个描述符,并且指向shell终端。 所以标准输出、标准错误输出在shell上输出,标准输入在shell上输入。
当然我们也可以修改这3个描述符的指向,比如将标准输出指向一个文件,那么在程序里printf、cout输出的内容将不在shell上显示,而是存入了文件里,常见的命令比如:
./a.out > aaa.txt
将标准输出存入aaa.txt文件中。
磁盘文件
在C语言里使用fopen
打开文件,fread
读取文件,fwrite
写入文件,fclose
关闭文件。
在C++语言里有ifstream
读取文件,ofstream
写入文件。但通常更习惯于使用C语言提供的接口读写文件。
在Linux系统api里提供了open
打开文件,read
读取文件,write
写入文件,close
关闭文件。实际上C和C++库函数最终调用了系统api函数完成真正的读写功能。
套接字
套接字用于网络数据的读写,套接字相关函数操作的对象都是socket套接字,Linux提供了socket
函数用于创建一个socket对象。
管道
管道是一种进程间通信接口,既可用于两个不同进程间通信,也可以用于同一个进程内部通信,Linux提供了pipe
函数用于创建一个管道。
描述符分配规则
下面一段代码(fd.c)输出了描述符具体的数值,用于分析文件描述符的分配规则。
#include <unistd.h>#include <fcntl.h>#include <sys/socket.h>#include <arpa/inet.h>int main(){ /*标准输入、输出*/ printf("stdin = %d\n", STDIN_FILENO); printf("stdout = %d\n", STDOUT_FILENO); printf("stderr = %d\n\n", STDERR_FILENO); /*打开两个磁盘文件*/ int fd1 = open("./a1.txt", O_RDONLY); int fd2 = open("./a2.txt", O_RDONLY); printf("fd1 = %d\n", fd1); printf("fd2 = %d\n\n", fd2); /*创建两个套接字*/ int sfd1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int sfd2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); printf("sfd1 = %d\n", sfd1); printf("sfd2 = %d\n\n", sfd2); /*关闭之前打开的两个磁盘文件*/ printf("close fd1 fd2\n"); close(fd1); close(fd2); /*创建一个管道*/ int pipefd[2]; pipe(pipefd); printf("pipefd1 = %d\n", pipefd[0]); printf("pipefd2 = %d\n\n", pipefd[1]); /*再次打开刚才那两个磁盘文件*/ int fd3 = open("./a1.txt", O_RDONLY); int fd4 = open("./a2.txt", O_RDONLY); printf("fd3 = %d\n", fd3); printf("fd4 = %d\n\n", fd4); getchar(); return 0;}
运行结果:
stdin = 0stdout = 1stderr = 2fd1 = 3fd2 = 4sfd1 = 5sfd2 = 6close fd1 fd2pipefd1 = 3pipefd2 = 4fd3 = 7fd4 = 8
代码分析:
(1)启动程序后,首先测试标准输入、输出、错误输出的fd(File descriptor,简称fd)值,分别为0、1、2。
(2)然后测试打开磁盘文件a1.txt、a2.txt后返回的fd值,若没有这个文件,可先使用命令在测试代码目录下创建两个空文件
touch a1.txt a2.txt
测试结果显示,打开两个磁盘文件返回的fd为3、4,因为0、1、2已经被标准输入输出占用。
(3)再测试套接字的fd,创建两个套接字对象,返回的fd分别为5、6。
(4)关闭第2步打开的两个磁盘文件fd。
(5)再测试管道的fd,创建一个管道,返回的两个fd分别为3、4,这说明已经关闭的fd可再次使用。
(6)再次打开那两个磁盘文件,返回的fd分别为7、8。
分配规则总结:
(1)Linux 系统里标准输入输出、磁盘文件、套接字、管道共用一套fd编号。
(2)fd编号总是从0开始逐步递增。
(3)若某个已使用的fd被关闭释放后,可以被再次使用。
另外我们可以在/proc/(进程id)/fd目录下更直观的看到进程fd状态。
由于Linux系统将多种读写对象统一抽象为文件类型,并提供一致的接口,因此在实际开发中我们可以更为灵活的处理文件对象。
比如select/epoll等函数一般用于检测socket的读写状态,但我们也可以将其用于检测标准输入输出、管道的读写状态,这就是本文分析文件描述符的意义。
- 跨平台C++服务器程序开发 (3)Linux文件描述符
- 跨平台C++服务器程序开发 (2)服务器端口
- Linux服务器文件描述符最大值修改
- Linux加大服务器文件描述符
- linux之加大服务器文件描述符
- C++&wxWidgets 跨平台窗口程序开发(二,Linux篇)
- 跨平台C++服务器程序开发 (1)了解跨平台开发
- vs2010开发linux平台C程序 开发环境配置
- vs2010开发linux平台C程序 开发环境配置
- Linux C -> fsync -> 将缓存文件写入文件描述符
- linux文件描述符
- linux 文件描述符
- linux 文件描述符
- Linux文件描述符
- Linux文件描述符
- linux文件描述符
- linux文件描述符
- linux 文件描述符
- 将jar 作为linux服务程序运行的方法.
- 最小生成树 Kruskal算法
- 设计模式之代理模式(Proxy)
- POJ2251 Dungeon Master
- 找唯一数
- 跨平台C++服务器程序开发 (3)Linux文件描述符
- 利用Swagger Maven Plugin生成Rest API文档
- BZOJ 1087 SCOI 互不侵犯 状态DP
- Android控件架构与view,viewgroup的测量和绘制
- 函数表达式和闭包
- 用REST获得openvswitch ovsdb的信息
- js闭包
- Please ensure that adb is correctly located at……问题解决方案
- iOS中的事件传递和响应者链条