导言:

I/O输入输出是在主存和外部设备之间复制数据的过程。输入操作是从I/O设备复制数据到主存,而输出操作是从主存复制数据到I/O设备

I/O函数:

在linux中I/O函数根据使用用途大致分为三类
图片.png

标准I/O:

c语言定义了一组高级输入输出函数,成为标准I/O库,为程序员提供了Unix I/O的较高级别的替代。这个库提供了打开和关闭文件的函数(fopen和fclose)、读和写字节的函数(fread和fwrite)、读和写字符串的函数(fgets和fputs),以及复杂的格式化的I/O函数(scanf和printf)。
标准I/O库将一个打开的文件模型化为一个流。对于程序员而言,一个流就是一个指向FILE类型的结构的指针。每个ANSI C程序开始时都有三个打开的流 stdin、stdout和stderr,分别对应于标准输入、标准输出和标准错误。

Unix I/O函数:

Unix I/O模型是在操作系统内核中实现的。应用程序可以通过诸如open、close、lseek、read、write和stat这样的函数来访问Unix I/O。RIO和标准I/O函数都是基于Unix I/O函数来实现的。

read和write函数:

应用程序时通过分别调用read和write函数来执行输入和输出的

  1. ssize_t read(int fd,void *buf,size_t n);#参1描述符,参2字符串地址,参3读入长度
  2. ssize_t write(int fd,const void *buf,size_t n);#参1描述符,参2字符串地址,参3写入长度

read函数从秒输入为fd的当前文件位置复制最多n个字节到内存位置buf。返回值-1表示一个错误,而返回值0表示EOF。否则,返回值表示的是实际传送的字节数量。
write函数从内存位置buf复制至多n个字节到描述符fd的当前文件位置。
一个一字节一字节的从标准输入复制到标准输出的读取程序read:

  1. #include<stdio.h>
  2. #include <unistd.h>
  3. int main(){
  4. printf("client: PID %d\n",getpid());
  5. char c;
  6. while(read(STDIN_FILENO,&c,1)!=0)
  7. write(STDOUT_FILENO,&c,1);
  8. }

一个测试:

我们都知道,linux一切皆文件
运行上面的read程序:
图片.png
pid为21270
图片.png
在/proc/pid目录下存有该程序的信息,其中fd中有标准输入输出的软连接,我们可以通过这个软连接获得到描述符,然后用ioctl函数向其中写入数据,如果输入内容回显了说明read函数确实从标准输入中读取了数据:

  1. /*
  2. written by evoa(很感谢evoa师傅)
  3. 编译命令:gcc - g evoa_tql.c evoa_tql
  4. */
  5. #include <stdio.h>
  6. #include <fcntl.h>
  7. #include <termios.h>
  8. #include <sys/ioctl.h>
  9. #include <unistd.h>
  10. char *progname;
  11. static int usage() {
  12. printf("Usage: %s ttydev text\n", progname);
  13. return 2;
  14. }
  15. int main(int argc, char **argv) {
  16. int fd, argi;
  17. char *term = NULL;
  18. char *text = NULL;
  19. int t[2]={65,13},len=2; #写入65,13对应A与回车符
  20. progname = argv[0];
  21. argi = 1;
  22. if (argi < argc)
  23. term = argv[argi++];
  24. else {
  25. fprintf(stderr, "%s: no tty specified\n", progname);
  26. return usage();
  27. }
  28. if (argi < argc){
  29. text = argv[argi++];
  30. printf("text:%p,%d",&t,argi);
  31. }
  32. else {
  33. fprintf(stderr, "%s: no text specified\n", progname);
  34. return usage();
  35. }
  36. if (argi != argc) {
  37. fprintf(stderr, "%s: too many arguments\n", progname);
  38. return usage();
  39. }
  40. fd = open(term, O_RDONLY);
  41. if (fd < 0) {
  42. perror(term);
  43. fprintf(stderr, "%s: could not open tty\n", progname);
  44. return 1;
  45. }
  46. for (int i=0;i<len;i++){
  47. if (ioctl(fd, TIOCSTI, &t[i])) {
  48. perror("ioctl");
  49. return 1;
  50. }
  51. text++;
  52. }
  53. return 0;
  54. }

运行
图片.png图片.png
可以看到确实输出了大写的A,证明成功!