我最近在读CSAPP。它在10.9节中说,由于以下原因,不应将标准I / O与套接字一起使用:
(1)标准I / O的限制
限制1:输入功能紧随输出功能。在没有中间调用fflush,fseek,fsetpos或rewind的情况下,输入函数不能跟随输出函数。fflush函数清空与流关联的缓冲区。后三个函数使用Unix I / O lseek函数重置当前文件位置。
限制2:输出功能紧随输入功能。除非输入函数遇到文件结尾,否则输出函数不能跟随输入函数,而不会介入调用fseek,fsetpos或rewind。
(2)在套接字上使用lseek函数是非法的。
问题1:如果我违反限制会怎样?我写了一个代码片段,它工作正常。
问题2:绕过限制2,一种方法如下:
File *fpin, *fpout;
fpin = fdopen(sockfd, "r");
fpout = fdopen(sockfd, "w");
/* Some Work Here */
fclose(fpin);
fclose(fpout);
在教科书中说:
关闭线程程序中已经关闭的描述符是灾难的根源。
为什么?
由于您引用了两次关闭错误,因此您的解决方法无法按书面要求运行。只要没有干预操作都可以打开新的文件描述符,两次关闭对单线程程序是无害的(第二次关闭只会对进行无害的操作EBADF
),但是它们是多线程程序中的关键错误。考虑这种情况:
close(n)
。open
并返回n
它存储为int fd1
。close(n)
再次调用。open
再次调用并再次返回n
,并存储为fd2
。fd1
并实际写入由第二次调用open
而不是第一次调用打开的文件。这可能会导致大量文件损坏,信息泄漏(想象将密码写入套接字而不是本地文件)等。
但是,此问题很容易解决。无需fdopen
使用相同的文件描述符调用两次,只需使用dup
复制它并将副本传递给即可fdopen
。通过此简单的修复,stdio可以完美地与套接字一起使用。它仍然不适合异步事件循环使用,但是如果您将线程用于IO,则效果很好。
编辑:我想我没有回答您的问题1.如果您违反有关如何在stdio流上的输入和输出之间切换的规则,将会发生未定义的行为。这意味着对其进行测试并确认其“有效”是没有意义的。这可能意味着:
您正在使用的C实现为这种情况下的情况提供了一个定义(作为其文档的一部分),并且与您想要的行为匹配。在这种情况下,您可以使用它,但是您的代码将无法移植到其他实现中。因此,这样做被认为是非常不好的做法。要么,
您只是偶然获得预期的结果,通常是在所使用的实现上内部实现相关功能的方式的副作用。在这种情况下,无法保证它不会遇到无法按预期方式运行的极端情况,或者在将来的发行版中它将继续以相同的方式工作,等等。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句