UNP编程:47---IO管理(套接字配合标准IO的使用)

UNP编程 专栏收录该内容
47 篇文章 3 订阅

一、概念

  • 到目前为止的所有例子中,我们一直使用也称为Unix I/O——包括read、write这两个函数及它们的变体(recv、send等等)——的函数执行I/O。这些函数围绕描述符(descriptor)工 作,通常作为Unix内核中的系统调用实现
  • 执行I/O的另一个方法是使用标准I/O函数库(standard I/O library)。这个函数库由ANSI C标 准规范,意在便于移植到支持ANSI C的非Unix系统上。标准I/O函数库处理我们直接使用Unix I/O 函数时必须考虑的一些细节,譬如自动缓冲输入流和输出流。不幸的是,它对于流的缓冲处理可能导致我们同样必须考虑的一组新的问题。APUE第5章详细讨论了标准I/O函数库,[Plauger 1992]给出并讨论了标准I/O函数库的一个完整的实现
  • 标准I/O函数库也使用流(stream)这个称谓,譬如“打开一个输入流”或“刷写输 出流”。不要把它和我们将在第31章中讨论的流(STREAMS)子系统相混淆

二、套接字配合标准IO使用的注意事项

  • ①通过调用fdopen,可以从任何一个描述符创建出一个标准I/O流。类似地,通过调用 fileno,可以获取一个给定标准I/O流对应的描述符。我们第一次遇到fileno是在图6-9 中,当时我们想在一个标准I/O流上调用select。select只能用于描述符,因此我们不 得不获取那个标准I/O流的描述符
  • ②TCP和UDP套接字是全双工的。标准I/O流也可以是全双工的:只要以r+类型打开流即可, r+意味着读写。然而在这样的流上,我们必须在调用一个输出函数之后插入一个fflush、 fseek、fsetpos或rewind调用才能接着调用一个输入函数。类似地,调用一个输入函 数后也必须插入一个fseek、fsetpos或rewind调用才能调用一个输出函数,除非输入 函数遇到一个EOF。fseek、fsetpos和rewind这3个函数的问题是它们都调用lseek, 而lseek用在套接字上只会失败

解决上述读写问题的最简单方法是为一个给定套接字打开两个标准I/O流:一个用于读, 一个用于写(见下面的三)

三、标准IO的使用

  • 下面我们使用标准I/O代替read和writen重新编写图5-3中的TCP回射服务器程序。下面代码是改用标准I/O的str_echo函数版本。(这个版本存在一个我们稍后要讲解的问题)
void
str_echo(int sockfd)
{
    char line[MAXLINE];
    FILE *fpin, *fpout;
    
    fpin = Fdopen(sockfd, "r");
    fpout = Fdopen(sockfd, "w");

    while (Fgets(line, MAXLINE, fpin) != NULL)
    Fputs(line, fpout);
} 

标准IO使用时的缓冲问题

  • 服务器直到我们键入EOF字符才回射所有文本行的原因在于这里存在一个缓冲问题
  • 以下是实际发生的步骤:
    • 我们键入第一行输入文本,它被发送到服务器。
    • 服务器用fgets读入本行,再用fputs回射本行
    • 服务器的标准I/O流被标准I/O函数库完全缓冲。这意味着该函数库把回射行复制到输出 流的标准I/O缓冲区,但是不把该缓冲区中的内容写到描述符,因为该缓冲区未满。
    • 我们键入第二行输入文本,它被发送到服务器。
    • 服务器用fgets读入本行,再用fputs回射本行
    • 服务器的标准I/O函数库再次把回射行复制到输出流的标准I/O缓冲区,但是不把该缓冲 区中的内容写到描述符,因为该缓冲区仍未满。 同样的情形发生在我们键入的第三行文本上
    • 我们键入EOF字符,致使我们的str_cli函数(图6-13)调用shutdown,从而发送一个 FIN到服务器。 服务器TCP收取这个FIN,它被fgets读入,致使fgets返回一个空指针
    • str_echo函数返回到服务器的main函数(图5-12),子进程通过调用exit终止
    • C库函数exit调用标准I/O清理函数(APUE第162~164页①)。之前由我们的fputs调用填 入输出缓冲区中的未满内容现被输出。
    • 服务器子进程终止,致使它的已连接套接字被关闭,从而发送一个FIN到客户,完成TCP 的四分组终止序列
    • 我们的str_cli函数收取并输出由服务器回射的三行文本。
    • str_cli接着在其套接字上收到一个EOF,客户于是终止

五、使用标准IO的注意事项

  • 尽量避免在套接字上使用标准IO
  • 既然套接字不是终端设备,上面的str_echo函数的上述问题就在于输出流(fpout) 是完全缓冲的。本问题有两个解决办法:第一个办法是通过调用setvbuf迫使这个输出流变为 行缓冲。第二个办法是在每次调用fputs之后通过调用fflush强制输出每个回射行。然而在现 实使用中,这两种办法都易于犯错,与Nagle算法(如7.9节所述)的交互可能也成问题。大多数情况下,最好的解决办法是彻底避免在套接字上使用标准I/O函数库,并且如3.9节所述在缓冲区而不是文本行上执行操作。当标准I/O流的便利性大过对缓冲带来的bug的担忧时,在套接字 上使用标准I/O流也可能可行,但这种情况很罕见
  • 要注意的是标准I/O库的某些实现在描述符大于255情况下还有一个问题。这一点对于需 处理大量描述符的网络服务器可能也是一个问题。检查你的头文件中定义的FILE 结构,看看存放描述符的变量是什么类型
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值