65.9K
CodeProject 正在变化。 阅读更多。
Home

一个典型的Linux C应用程序:允许简单的基于IPC管道的标准I/O端口

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (9投票s)

2008年10月16日

公共领域

4分钟阅读

viewsIcon

47508

downloadIcon

461

演示如何创建一个简单的应用程序,该应用程序通过终端标准I/O端口进行交互,以提供基于IPC管道的进程间通信

图 1:makeupper 与其他两个进程的管道连接

引言

典型的Linux(或UNIX)终端应用程序,如cat命令,提供了三种输入数据的方式

  • 通过将文件名作为参数传递:cat file.txt <enter>
  • 通过规范模式输入:cat <enter>
    • 规范模式是一种终端输入模式,以行为单位进行处理。这意味着程序在输入新行(CRLF)或EOF(文件结束)字符后读取信息。
  • 通过创建管道连接将数据发送到进程(或从进程接收数据)

    cat file.txt | more <enter>

本文演示了如何创建一个小型应用程序(makeupper),该应用程序支持这三种数据输入方式。

注意:源代码应该可以在任何UNIX系统或Linux发行版中无错误地编译。

终端输入/输出

在Linux和所有其他UNIX系统中(如IBM-AIX),从文件读取数据和从终端读取数据,或者将数据写入文件和将数据写入屏幕之间没有区别 - 特别是当数据只包含字符字符串时。

终端提供三个I/O端口

  • 标准输入:默认是键盘
  • 标准输出:默认是终端屏幕
  • 标准错误:默认是终端屏幕

有两种函数集用于处理这些I/O端口

  • 低级I/O系统调用:使用文件描述符来访问标准输入、输出和错误。
  • 标准I/O库:使用,实现为指向FILE*结构的指针(#include <stdio.h>)。

图 2:低级系统调用和标准I/O库函数

注意:您可以获取有关低级系统调用的更多信息:readwriteopenselectclose

源代码包含一个名为test.c的小应用程序,它通过将一个string打印到终端屏幕(标准输出)来演示低级系统调用和标准I/O库函数的使用。源代码是最简单的

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main ( int _argc, char *_argv[] )
{
    char *ptr = "This is an output test!\n";

    printf( ptr );
    fprintf( stdout, ptr );
    write( 1, ptr, strlen(ptr) );

    return 0;
}

使用C编译器构建test.c

cc -o test test.c

当您执行./test时,将获得以下输出

图 3:./test 输出

看到了吗?由ptr指向的字符串"This is an output test!"通过三个不同的函数被打印到屏幕(标准输出)

  • printf标准I/O库的一部分,默认始终将string打印到标准输出
  • fprintf标准I/O库的一部分。注意第一个参数stdout流将ptr string重定向到标准输出(或屏幕)。
  • write低级系统调用。注意第一个参数1,它是标准输出的文件描述符。

Makeupper示例

源代码中还有两个示例:makeupper.cmakeupper2.c。它们做的事情相同。区别在于makeupper.c使用低级系统调用,而makeupper2.c使用标准I/O库。

makeupper示例非常简单。它的目的是将输入数据中的字母转换为大写并打印到标准输出。然而,它演示了如何从标准输入和文件读取。第一个示例makeupper.c使用低级系统调用

/* Makeupper.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main ( int _argc, char *_argv[] )
{
    int  fd_main = 0;
    char ch = 0;

    fd_main = _argc == 1 ? 0 : open(_argv[1], O_RDONLY);

    if ( fd_main == -1 )
    {
       perror("input");
       exit(-1);
    }

    while ( read( fd_main, &ch , 1 ) )
    {
       ch = toupper(ch);
       write( 1, &ch, 1 );
    }

    close(fd_main);

    return 0;
}

注意该行

fd_main = _argc == 1 ? 0 : open(_argv[1], O_RDONLY);

如果没有传递文件路径参数,则fd_main假定为标准输入描述符。当传递文件作为参数时,使用open系统调用来打开文件。

makeupper2.c使用标准I/O库函数而不是系统调用

/* Makeupper2.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main ( int _argc, char *_argv[] )
{
    FILE *f_file = NULL;
    char ch = 0;

    f_file = _argc == 1 ? stdin : fopen(_argv[1], "r");

    if ( f_file == NULL )
    {
       perror("input");
       exit(-1);
    }

    while ( !feof(f_file) )
    if ( (ch = fgetc(f_file)) > 0 )
        fputc( toupper(ch), stdout );

    fclose(f_file);

    return 0;
}

构建两个示例

  • cc -o makeupper makeupper.c
  • cc -o makeupper2 makeupper2.c

通过不带参数执行./makeupper(或./makeupper2),它将在规范模式下启动。按下回车后,makeupper会接收该行。要退出规范模式,您应该按CTRL+DCTRL+\

图 4:./makeupper - 规范模式

您也可以传递一个文件路径

图 5:./makeupper - 将test.c的内容打印到标准输出

或者makeupper可以从进程的标准输入接收输出

图 6:./makeupper2 - ls -ltr输出通过PIPE从屏幕(标准输出)重定向到makeupper2的标准输入

重定向I/O

您可以将标准输出和错误重定向到文件或设备(/dev/...)。为了说明这一点,请键入并编译以下代码(您可以将其命名为test2.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( int _argc, char *_argv[] )
{
    char *p1 = "printed to standard output via stdlib.\n";
    char *p2 = "printed to standard error via stdlib.\n";
    char *p3 = "printed to standard output via low-level calls.\n";
    char *p4 = "printed to standard error low-level calls.\n";

    fprintf( stdout, p1 );
    fprintf( stderr, p2 );

    write ( 1, p3, strlen(p3) );
    write ( 2, p4, strlen(p4) );

    return 0;
}

有四个指针指向四个字符串。p1 p3被打印到标准输出,而p2 p4被打印到标准错误。

构建它

cc -o test2 test.c

通过执行./test2,我们得到

  1. ./test2 - 您将所有字符串打印到屏幕。
  2. ./test2 >file.txt - 将标准输出重定向到file.txt。注意只有p1 p3 字符串保存在file.txt中。
  3. ./test2 2>file.txt 将标准错误重定向到file.txt。注意只有p2 p4 字符串保存在file.txt中。
  4. ./test2 >file.txt 2>&1 将输出和错误都重定向到file.txt。注意技巧2>&1(表示将标准错误重定向到标准输出)。

如果您想追加到现有文件:./test2 >>file.txt./test2 >>file.txt 2>&1

希望这有所帮助。

历史

  • 2008年10月14日:第一个版本
© . All rights reserved.