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






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

引言
典型的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>)。

注意:您可以获取有关低级系统调用的更多信息:read、write、open、select、close。
源代码包含一个名为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时,将获得以下输出

看到了吗?由ptr指向的字符串"This is an output test!"通过三个不同的函数被打印到屏幕(标准输出)
- printf:标准I/O库的一部分,默认始终将- string打印到标准输出
- fprintf:标准I/O库的一部分。注意第一个参数- stdout流将- ptr string重定向到标准输出(或屏幕)。
- write:低级系统调用。注意第一个参数- 1,它是标准输出的文件描述符。
Makeupper示例
源代码中还有两个示例:makeupper.c和makeupper2.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+D或CTRL+\

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

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

重定向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,我们得到

- ./test2 - 您将所有字符串打印到屏幕。
- ./test2 >file.txt - 将标准输出重定向到file.txt。注意只有p1和p3字符串保存在file.txt中。
- ./test2 2>file.txt 将标准错误重定向到file.txt。注意只有p2和p4字符串保存在file.txt中。
- ./test2 >file.txt 2>&1 将输出和错误都重定向到file.txt。注意技巧2>&1(表示将标准错误重定向到标准输出)。
如果您想追加到现有文件:./test2 >>file.txt 或./test2 >>file.txt 2>&1。
希望这有所帮助。
历史
- 2008年10月14日:第一个版本


