72-套接字与标准I/O

116 篇文章 22 订阅

之前我们使用 read,write 及其他们的变体(recv, send) 函数读写 I/O,这些函数都是围绕着描述符工作的。我们将这一类 I/O 称为 Unix I/O.

我们也可以使用标准 I/O 函数库来读写 I/O,它由 ANSI C 标准进行规范,比如 fputs, fgets 等等。

当然了,fputs, fgets 这一类函数也可以用于套接字,不过这需要从描述符创建一个标准 I/O 流,主要使用函数 fdopen. 有一个与 fdopen 函数功能相反的函数是 fileno,它从标准 I/O 流创建出一个文件描述符。

FILE *fdopen(int fd, const char *mode);
int fileno(FILE *stream);

1. 使用标准 I/O 改写 TCP 回射服务器

void doServer(int sockfd) {
  int ret;
  char buf[4096];
  FILE *fpin, *fpout;
  // 根据描述符创建标准 I/O 流
  fpin = fdopen(sockfd, "r");
  fpout = fdopen(sockfd, "w");

  while(fgets(buf, 4096, fpin) != NULL) {
    // 转换成大写
    toUpper(buf, strlen(buf));
    ret = fputs(buf, fpout);
    if (ret == EOF) {
      puts("fputs error");
    }
  }
  // 根据命令行参数控制
  if (g_option.flush) fflush(fpout);
}

2. 程序路径

代码托管在 gitos 上,请使用下面的命令获取:

git clone https://git.oschina.net/ivan_allen/unp.git

如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本节程序所使用的程序路径是 unp/program/advcio/stdin/echo.cc.

3. 实验结果

下面两个实验中,在客户端中随便输入数据,然后按 CTRL D 退出。

  • 启动服务器,不开启缓冲区刷新
./echo -s -h mars


这里写图片描述
图1 服务器未刷新缓冲,客户端运行情况

我们看到客户端并没有收到回射的数据。

  • 启动服务器,并开启缓冲区刷新
./echo -s -h mars --flush


这里写图片描述
图2 服务器子进程退出时刷新了缓冲区,客户端收到回射数据

4. 实验结果分析

从图 1 和图 2 中我们看到,这两个结果并不是我们想要的。图 1 中根本就没有得到正确的结果,图2 虽然最后也得到了数据,但是也是在客户端准备退出的时候才收到。

出现这种情况的原因在于标准 I/O 是带有缓冲的。标准 I/O 函数库有三类缓冲:

  • 完全缓冲(fully buffering),这意味着只在出现下列情况时才发生 I/O: 缓冲区满,进程显式调用 fflush,进程调用 exit 终止自身(这一种和图 1 中的现象并不一致)。
  • 行缓冲(line buffering),这意味着出现下列情况时才发生 I/O: 碰到一个换行符,进程调用 fflush,或进程调用 exit 终止自身。
  • 不缓冲(unbuffering),意味着每次调用标准 I/O 输出函数都发生 I/O.

标准 I/O 函数库的大多数 Unix 实现使用如下规则:

  • 标准错误输出总是不缓冲。
  • 标准输入和标准输出完全维修部,除非它们指代终端设备(这种中下它们行缓冲)。
  • 所有其他 I/O 流都是完全缓冲,除非它们指代终端设备(这种情况下它们行缓冲)

既然套接字不是终端设备,因此它是完全缓冲的。

unp 建议:

避免在套接字上使用标准 I/O 函数库。

5. 总结

  • 知道如何在套接字上使用标准 I/O 函数库
  • 避免在套接字上使用标准 I/O 函数库
  • 0
    点赞
  • 1
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值