<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->
-
使用标准I/O 流的必要性
@ Linux 的stdio 实用程序符合ANSF C3.159.1989 标准,这种接口标准有助于程序移植到各种机器平台上。
@ read,write 函数不能一次返回一行或者一个数据,而是一次性返回所有数据。而使用标准I/O 可以实现一次返回一行或者一个数据,写操作时,使用标准I/O 可以逐字写入,同时不会带来太大的访问负担。使用write 写操作时需要付出较大的代价。
@ stdio 软件包还提供了输入/ 输出缓冲。使用缓冲技术可以显著的提高应用程序的性能。
-
相关的部分标准I/O 函数:
fopen,fread,fwrite,fflush,fclose
可以 man stdio 查看用法
-
连接套接口与流
//10.1
int s;// 套接口
FILE* io;// 流
s = socket (PF_INET,SOCK_STREAM,0);
...
io = fdopen(s,”r+”);
if (io == NULL ) {
//report error
}
-
关闭流套接口
FILE *fdopen(int fd, const char *mode);
作用:将一个流与一个已经存在的文件描述符相联系。
@ 传递给fdopen 的fd 就是实际用于物理读写的文件描述符。没有dup() 对文件描述符进行复制,如果调用close(s) 执行套接口的关闭操作,意味着关闭流变量io 正在使用的文件描述符,这是不可能的。( 这一句没读懂)
@ 利用fclose(io) 可以正确的关闭套接口s 。
它的执行过程如下,
1> 将缓冲区数据会写到文件描述符( 或者文件,套接口) 如果有缓冲区数据,系 统自动调用write 函数进行回写。
2> 利用close 关闭与流相应的文件描述符。
3> 利用free 函数释放缓冲区和FILE 结构空间。
-
分开使用读写流
示例10.1 中的流io 允许同时进行读和写,这是允许的。但在实际应用中,分别打开输入和输出流会更安全,因为实现一个读写流缓冲比单独的读或则写流的缓冲技术要复杂,且当I/O 流由写( 读) 模式切换到读( 写) 模式时,需要执行fgetpos 调用。这样,分开后会有更好的缓冲性能。避免了缓冲区的交互和对fgetpos 的调用。
//10.2 创建分离读写流
int s;// 套接口
FILE* rx;// 读流
FILE* tx;// 写流
s = socket(PF_INET, SOCK_STREAM,0);
...
rx = fdopen(s,”r”);
if (rx == NULL)
//report error
tx = fdopen(dup(s),”w”);// 注意dup 函数
if (tx==NULL)
//report error
使用dup 复制一个套接口的原因是:不同的流使用不同的问价描述符。最简单的情 况,当调用 fclose(tx) 时,不会关闭rx 正在使用的同一个套接口。
-
dup 介绍
int dup (int oldfd);
将套接口s 作为输入参数,得到一个新的文件描述符。该描述符也指向同一个套接
口s 。执行了复制操作后,只有各个描述符都关闭时,套接口本身才被内核关闭。
( 如果不使用shutdown 函数)
-
关闭套接口上的读/ 写流
fclose(rx);fclose(tx);
// 该操作完成了,缓冲区回写,关闭相应的文件描述符,释放缓冲区,释放FILE 对象管理的流。
-
Shutdown 的使用
建立套接口上本地进程和远程进程之间的通信连接后,考虑以下三种基本情形:
1> 只关闭写端—进程等待数据,而不再写数据。
fflush (tx);// 清除缓冲区中可能存在的数据
shutdown(fileno(tx),SHUT_WR);// 关闭套接口的写端
fclose (tx);// 关闭写流
2> 只关闭读端—进程试探写数据,而不再读数据。
shutdown(fileno(rx),SHUT_RD);// 关闭套接口的读端
fclose (rx);// 关闭读流
// int fileno(FILE* stream);// 由流得到流对应的文件描述符
3> 同时关闭读写两端—进程不再读写数据。
fclose(tx);// 关闭写流,隐式的进行了数据的回写,不必再调用fflush
shutdown(fileno(rx),SHUT_DOWN);// 结束套接口的读和写, 没有此步可能造成阻塞,
-
// 因为如果套接口上还有其他打开的文件描述符,会造成进程的阻塞( 只有关闭// 了套接口上的最后一个描述符,才真正关闭套接口)
fclose(rx);//
补充:shutdown ,不考虑套接口上打开的文件描述符的个数,他会影响该套接口上所有文件描述符,从而影响连接到该套接口的所有的流。
-
定义缓冲操作
缓冲写,可以减少系统调用write函数的频率。缓冲读,可以使read一次读入更多的数据,这样可以提高系统的I/O性能。
Linux中的FILE流有三种基本缓冲模式:
* 全缓冲(块缓冲)
* 线形缓冲
* 无缓冲
如果与流对应的文件描述符为终端设备,输入/输出常设置成线性缓冲模式。而文件常设置为全缓冲模式。
套接口交互是文本行方式,通常采用线性缓冲模式,用户无需调用fflush()将最后的文本行写到套接口。如果使用全缓冲模式,则进行套接口上的物理写时,要调用fflush()。否则,数据有可能滞留在缓冲区,导致应用程序无限期的等待。
相关函数,setbuf,setbuffer,setlinebuf,setvbuf *.
下面是个综合的例子片段,