zoukankan      html  css  js  c++  java
  • 进程间通信之数据传输--管道及重定向

    数据传输直观图

    代表:管道、FIFO、消息队列、socket.

     

    重定向介绍

    在命令行运行的每个程序都会有三个数据流与之相连接:

    • STDIN (0) - 标准输入(传给程序的数据)
    • STDOUT (1) - 标准输出(程序打印的数据,默认输出至终端)
    • STDERR (2) - 标准错误(针对错误信息,默认也是输出至终端)

    利用管道或重定向,可以以更有趣有效的方式来建立起程序和文件之间的数据流连接。

    下面将会举若干个例子演示管道及重定向在命令行下的运行情况。

    重定向到一个文件

    通常情况下我们会在屏幕上获得输出信息,在大多数时候这是非常方便的,但是有时候我们希望将输出保存在一个文件中,以便将数据传给另外一个系统或用户。大于符号(>)可以将命令行下的程序输出(或者说发送给STDOUT的任意数据)存储在一个文件中,而不是打印在屏幕上,来看一个例子。

    先分析一下图中的命令:

    • Line 1 首先看下当前目录有哪些文件
    • Line 3 再运行一次 ls 命令,这次我们使用 > 来告诉终端保留输出到 myoutput文件中。你也许注意到了,在保留之前我们并不需要创建该文件,如果文件不存在的话,终端会自动创建该文件。
    • Line 4 可以看到当前目录下已经多了一个新文件
    • Line 6 看一下文件里面保存了什么内容

    一些观察

    在上述的例子中你应该注意到了,保存在文件中的输出是一行一个文件名,而不是像屏幕打印那样,所有的文件名在一行内连续输出。这是因为屏幕的宽度是已知的,程序可以格式化它的输出来适应屏幕,而当我们重定向输出时,可能输出到一个文件,也可能是其他地方,因此最稳妥的方式是一个输出项一行,这样的话我们可以更容易的处理这些数据,在稍后的章节中我们将会看到这样做的便利性。

    需要记住的是:当使用管道或重定向时,实际的数据内容始终是一样的,只是数据格式可能会跟通常打印到屏幕上的样式有稍许不同。

    你可能还注意到了,我们创建的用来存储输出数据的文件也在内容列表中,这是因为:文件首先被创建(假如文件不存在),然后程序再运行然后输出信息保存在该文件中。

    内容比较简单,后续不翻译了。。直接看吧。。。

    Saving to an Existing File

    If we redirect to a file which does not exist, it will be created automatically for us. If we save into a file which already exists, however, then it's contents will be cleared, then the new output saved to it.

    We can instead get the new data to be appended to the file by using the double greater than operator ( >> ).

    Redirecting from a File

    If we use the less than operator ( < ) then we can send data the other way. We will read data from the file and feed it into the program via it's STDIN stream.

    A lot of programs (as we've seen in previous sections) allow us to supply a file as a command line argument and it will read and process the contents of that file. Given this, you may be asking why we would need to use this operator. The above example illustrates a subtle but useful difference. You'll notice that when we ran wc supplying the file to process as a command line argument, the output from the program included the name of the file that was processed. When we ran it redirecting the contents of the file into wc the file name was not printed. This is because whenever we use redirection or piping, the data is sent anonymously. So in the above example, wc recieved some content to process, but it has no knowledge of where it came from so it may not print this information. As a result, this mechanism is often used in order to get ancillary data (which may not be required) to not be printed.

    We may easily combine the two forms of redirection we have seen so far into a single command as seen in the example below.

    Redirecting STDERR

    Now let's look at the third stream which is Standard Error or STDERR. The three streams actually have numbers associated with them (in brackets in the list at the top of the page). STDERR is stream number 2 and we may use these numbers to identify the streams. If we place a number before the > operator then it will redirect that stream (if we don't use a number, like we have been doing so far, then it defaults to stream 1).

    Maybe we wish to save both normal output and error messages into a single file. This can be done by redirecting the STDERR stream to the STDOUT stream and redirecting STDOUT to a file. We redirect to a file first then redirect the error stream. We identify the redirection to a stream by placing an & in front of the stream number (otherwise it would redirect to a file called 1).

    Piping

    So far we've dealt with sending data to and from files. Now we'll take a look at a mechanism for sending data from one program to another. It's called piping and the operator we use is ( | ) (found above the backslash ( ) key on most keyboards). What this operator does is feed the output from the program on the left as input to the program on the right. In the example below we will list only the first 3 files in the directory.

    We may pipe as many programs together as we like. In the below example we have then piped the output to tail so as to get only the third file.

    Tip:

      Any command line arguments we supply for a program must be next to that program.

    Tip:

      I often find people try and write their pipes all out in one go and make a mistake somewhere along the line. They then think it is in one point but in fact it is another point. They waste a lot of time trying to fix a problem that is not there while not seeing the problem that is there. If you build your pipes up   incrementally then you won't fall into this trap. Run the first program and make sure it provides the output you were expecting. Then add the second program and check again before adding the third and so on. This will save you a lot of frustration.

      You may combine pipes and redirection too.

    More Examples

    Below are some more examples to give an idea of the sorts of things you can do with piping. There are many things you can achieve with piping and these are just a few of them. With experience and a little creative thinking I'm sure you'll find many more ways to use piping to make your life easier.

    All the programs used in the examples are programs we have seen before. I have used some command line arguments that we haven't covered yet however. Look up the relevant man pages to find out what they do. Also you can try the commands yourself, building up incrementally to see exactly what each step is doing.

    In this example we are sorting the listing of a directory so that all the directories are listed first.

    Summary

    Stuff We Learnt

      >
    Save output to a file.
      >>
    Append output to a file.
      <
    Read input from a file.
      2>
    Redirect error messages.
      |
    Send the output from one program as input to another program.
    Important Concepts
      Streams
    Every program you may run on the command line has 3 streams, STDIN, STDOUT and STDERR.

    以上原文摘抄自:https://ryanstutorials.net/linuxtutorial/piping.php

     C程序演示 pipe()用法

    Write Linux C program to create two processes P1 and P2. P1 takes a string and passes it to P2. P2 concatenates the received string with another string without using string function and sends it back to P1 for printing.

    Examples:

    Other string is: forgeeks.org
    
    Input  : www.geeks
    Output : www.geeksforgeeks.org
            
    Input :  www.practice.geeks
    Output : practice.geeksforgeeks.org

    Explanation:

    • To create child process we use fork(). fork() returns :
      • <0 fail to create child (new) process
      • =0 for child process
      • >0 i.e process ID of the child process to the parent process. When >0 parent process will execute.
    • pipe() is used for passing information from one process to another. pipe() is unidirectional therefore, for two-way communication between processes, two pipes can be set up, one for each direction.
       Example: 
       int fd[2];
       pipe(fd);
       fd[0]; //-> for using read end
       fd[1]; //-> for using write end
       

    Inside Parent Process : We firstly close the reading end of first pipe (fd1[0]) then write the string though writing end of the pipe (fd1[1]). Now parent will wait until child process is finished. After the child process, parent will close the writing end of second pipe(fd2[1]) and read the string through reading end of pipe (fd2[0]).

    Inside Child Process : Child reads the first string sent by parent process by closing the writing end of pipe (fd1[1]) and after reading concatenate both string and passes the string to parent process via fd2 pipe and will exit.

    // C program to demonstrate use of fork() and pipe() 
    #include<stdio.h> 
    #include<stdlib.h> 
    #include<unistd.h> 
    #include<sys/types.h> 
    #include<string.h> 
    #include<sys/wait.h> 
    
    int main() 
    { 
        // We use two pipes 
        // First pipe to send input string from parent 
        // Second pipe to send concatenated string from child 
    
        int fd1[2]; // Used to store two ends of first pipe 
        int fd2[2]; // Used to store two ends of second pipe 
    
        char fixed_str[] = "forgeeks.org"; 
        char input_str[100]; 
        pid_t p; 
    
        if (pipe(fd1)==-1) 
        { 
            fprintf(stderr, "Pipe Failed" ); 
            return 1; 
        } 
        if (pipe(fd2)==-1) 
        { 
            fprintf(stderr, "Pipe Failed" ); 
            return 1; 
        } 
    
        scanf("%s", input_str); 
        p = fork(); 
    
        if (p < 0) 
        { 
            fprintf(stderr, "fork Failed" ); 
            return 1; 
        } 
    
        // Parent process 
        else if (p > 0) 
        { 
            char concat_str[100]; 
    
            close(fd1[0]); // Close reading end of first pipe 
    
            // Write input string and close writing end of first 
            // pipe. 
            write(fd1[1], input_str, strlen(input_str)+1); 
            close(fd1[1]); 
    
            // Wait for child to send a string 
            wait(NULL); 
    
            close(fd2[1]); // Close writing end of second pipe 
    
            // Read string from child, print it and close 
            // reading end. 
            read(fd2[0], concat_str, 100); 
            printf("Concatenated string %s
    ", concat_str); 
            close(fd2[0]); 
        } 
    
        // child process 
        else
        { 
            close(fd1[1]); // Close writing end of first pipe 
    
            // Read a string using first pipe 
            char concat_str[100]; 
            read(fd1[0], concat_str, 100); 
    
            // Concatenate a fixed string with it 
            int k = strlen(concat_str); 
            int i; 
            for (i=0; i<strlen(fixed_str); i++) 
                concat_str[k++] = fixed_str[i]; 
    
            concat_str[k] = ''; // string ends with '' 
    
            // Close both reading ends 
            close(fd1[0]); 
            close(fd2[0]); 
    
            // Write concatenated string and close writing end 
            write(fd2[1], concat_str, strlen(concat_str)+1); 
            close(fd2[1]); 
    
            exit(0); 
        } 
    } 
    Input : www.geeks
    Output : Concatenated string
             www.geeksforgeeks.org

    以上示例摘抄自:https://www.geeksforgeeks.org/c-program-demonstrate-fork-and-pipe/

    Why do I need to close fds when reading and writing to the pipe?

    
    

    Your pipe is a unidirectional stream - with a file descriptor for each end. It is not necessary to close() either end of the pipe to allow data to pass along it.

    
    

    if your pipe spans processes (i.e. is created before a fork() and then the parent and child use it to communicate) you can have one write and and one read end. Then it is good practice to close the unwanted ends of the pipe. This will

    
    
    • make sure that when the writing end closes the pipe it is seen by the read end. As an example, say the child is the write side, and it dies. If the parent write side has not been closed, then the parent will not get "eof" (zero length read()) from the pipe - because the pipe has a open write-end.
    • make it clear which process is doing the writing and which process is doing the reading on the pipe.
    
    

    if your pipe spans threads (within the same process), then do not close the unwanted ends of the pipe. This is because the file descriptor is held by the process, and closing it for one thread will close it for all threads, and therefore the pipe will become unusable.

    摘抄自:https://stackoverflow.com/questions/976015/why-do-i-need-to-close-fds-when-reading-and-writing-to-the-pipe

    
    
    
    
  • 相关阅读:
    去除aspx生成的页面最开始的空行
    单个方框内图片垂直水平居中和等比例缩小(支持所有浏览器)
    .net里怎样在Main方法之前执行代码?
    WIN7系统盘空间不够用解决办法
    语音识别工具箱之HTK安装与使用
    一个VC中的DLL导出类的例子
    c++ 随机数 产生不重复的随机数
    android开发 NDK 编译和使用静态库、动态库
    c++指针 初识
    c++ UTF8和Unicode 互转
  • 原文地址:https://www.cnblogs.com/miaoxiong/p/11046034.html
Copyright © 2011-2022 走看看