应用程序可以通过诸如open、close、lseek、read、write和stat这样的函数来访问文件或I/O设备。更高级别的还有标准I/O及RIO( CS:AP网站参考代码 ,为了修补read等系统IO函数的不足而撰写的健壮的包装函数,它们自动处理不足值,为读文本行提供一种高效的带缓冲的方法。)

在实际编程中如何选用这些函数呢?下面提供一些基本原则:

  • 只要又可能就使用标准I/O。特别是对磁盘和终端设备来说,标准函数是首选方法。
  • 不要使用scanf或rio_readlineb来读二进制文件。它们是设计用来读取文本文件的。因为二进制文件中的0xa正好是文本文件中的换行符(代表行终止),而在二进制文件中这又非它的本意。
  • 对网络套接字的I/O使用RIO函数。为毛不用标准IO呢?因为标准I/O函数的使用有两个限制。

    1.跟在输出函数之后的输入函数的限制。在它们之间之间如果没有fflush、fseek、fsetpos、rewind的调用,一个输入函数是不能跟在一个输出函数之后的。
    2. 跟在输入函数之后的输出函数的限制。在它们之间之间如果没有fseek、fsetpos、rewind的调用,一个输入函数是不能跟在一个输出函数之后的,除非该输入函数遇到了一个文件结束。

这些限制给网络应用带来了问题,因为在对套接字使用lseek是非法的。如果说第一个限制我们可以在每个输入函数之前插入刷新缓冲区的函数来避免,而第二个限制的满足要求对同一个打开的套接字描述符打开两个流,一个用来写,一个用来读:

FILE *fpin,*fpout;
fpin = fdopen(sockfd, "r");
fpout = fdopen(sockfd, "w");

但是,这样要求应用程序在结束时需要在两个流上调用 fclose函数:

fclose(fpin);
fclose(fpout);

以上两条语句都试图关闭同一个底层的套接字描述符,所以第二条语句肯定会失败。对顺序执行的程序一般问题不大,但对线程化的程序来说,关闭一个已经关闭的描述符是会导致灾难性后果的。
因此,建议在网络套接字上不适应用标准IO函数,而要使用健壮的RIO函数。

  • 如果你需要格式化输出,使用sprintf函数在内存中格式化一个字符串,然后用rio_writen把它发送出去;
  • 如果你需要格式化输入,使用rio_readlineb函数来读一个完整的文本行,然后用sscanf从文本行提取不同的字段。

获取更多知识,请点击关注:
嵌入式Linux&ARM
CSDN博客
简书博客