go语言快速入门 IPC之管道通信 8

熟悉Unix/C编程的应该对IPC也非常的熟悉,多进程之间的通信主要的手段有管道/信号量/共享内存/Socket等,而管道作为父子进程间进行少量数据传递的有效手段也得到了广泛的应用,在这篇文章中我们来看一下go语言中如何使用管道进行进程进行通信。

管道的使用

在linux下,管道被非常广泛地使用,一般在编程中我们实现了popen等的应用即可提供管道功能。而在命令行中使用地也非常多,|就是最为典型的管道的应用例子。shell会为|符号两侧的命令各创建一个脚本,将左侧的输出管道与右侧的输入管道进行连接,可以进行单向管道通信。

比如我们使用go env来确认go语言的环境变量,然后使用grep从中确认出GOROOT环境变量的值一般会如下这样做

[root@liumiaocn goprj]# go env |grep GOROOT
GOROOT="/usr/local/go"
[root@liumiaocn goprj]#
  • 1
  • 2
  • 3

实现的过程其实go env会启动一个进程, 而grep命令也会产生一个进程,grep的进程会在go env的标准输出中进行检索GOROOT的行的信息然后显示出来,而负责这两个进程间的通信的正是管道。

在c语言中,我们需要父进程中进行fork以及对父进程的基本信息进行处理,同时初期化连接的管道信息从而实现管道通信。接下来,我们来看一下在go语言中是如何实现的

调用操作系统命令

为了方便演示,我们使用标准库os中的api以调用操作系统的命令并在此基础上建立用于通信的管道

例子代码

[[email protected] goprj]# cat basic-ipc-pipe.go
package main

import "fmt"
import "os/exec"

func main() {
        //create cmd
        cmd_go_env := exec.Command("go", "env")
        //cmd_grep:=exec.Command("grep","GOROOT")

        stdout_env, env_error := cmd_go_env.StdoutPipe()
        if env_error != nil {
                fmt.Println("Error happened about standard output pipe ", env_error)
                return
        }

        //env_error := cmd_go_env.Start()
        if env_error := cmd_go_env.Start(); env_error != nil {
                fmt.Println("Error happened in execution ", env_error)
                return
        }

        a1 := make([]byte, 1024)
        n, err := stdout_env.Read(a1)
        if err != nil {
                fmt.Println("Error happened in reading from stdout", err)
        }

        fmt.Printf("Standard output of go env command: %s", a1[:n])
}
[[email protected] goprj]#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

执行结果

[root@liumiaocn goprj]# go run basic-ipc-pipe.go
Standard output of go env command: GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH=""
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build142715013=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
[root@liumiaocn goprj]#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

管道连接

通过调用exec.Start启动一个进程,通过StdoutPipe将此调用的输出管道也创建了出来,在这里,我们读取了此输出的信息,确实是go env命令的标准输出,接下来要做的事情就是将此输出的管道与grep命令的进程进行连接了。我们将上面的代码进一步充实:

例子代码

[[email protected] goprj]# cat basic-ipc-pipe.go
package main

import "fmt"
import "os/exec"
import "bufio"
import "bytes"

func main() {
        //create cmd
        cmd_go_env := exec.Command("go", "env")
        cmd_grep := exec.Command("grep", "GOROOT")

        stdout_env, env_error := cmd_go_env.StdoutPipe()
        if env_error != nil {
                fmt.Println("Error happened about standard output pipe ", env_error)
                return
        }

        //env_error := cmd_go_env.Start()
        if env_error := cmd_go_env.Start(); env_error != nil {
                fmt.Println("Error happened in execution ", env_error)
                return
        }
        /*
                a1 := make([]byte, 1024)
                n, err := stdout_env.Read(a1)
                if err != nil {
                        fmt.Println("Error happened in reading from stdout", err)
                        return
                }

                fmt.Printf("Standard output of go env command: %s", a1[:n])
        */
        //get the output of go env
        stdout_buf_grep := bufio.NewReader(stdout_env)

        //create input pipe for grep command
        stdin_grep, grep_error := cmd_grep.StdinPipe()
        if grep_error != nil {
                fmt.Println("Error happened about standard input pipe ", grep_error)
                return
        }

        //connect the two pipes together
        stdout_buf_grep.WriteTo(stdin_grep)

        //set buffer for reading
        var buf_result bytes.Buffer
        cmd_grep.Stdout = &buf_result

        //grep_error := cmd_grep.Start()
        if grep_error := cmd_grep.Start(); grep_error != nil {
                fmt.Println("Error happened in execution ", grep_error)
                return
        }

        err := stdin_grep.Close()
        if err != nil {
                fmt.Println("Error happened in closing pipe", err)
                return
        }

        //make sure all the infor in the buffer could be read
        if err := cmd_grep.Wait(); err != nil {
                fmt.Println("Error happened in Wait process")
                return
        }
        fmt.Println(buf_result.String())

}
[[email protected] goprj]#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

内容非常简单,无需过多解释,唯一需要注意的就是上一个例子中为了确认中间信息,读出管道的信息,但是此处读完了,输入管道就读不到了,所以注释掉了才能正常执行

执行结果

[root@liumiaocn goprj]# go run basic-ipc-pipe.go
GOROOT="/usr/local/go"

[root@liumiaocn goprj]#
  • 1
  • 2
  • 3
  • 4

从这里可以看出与go env |grep GOROOT是一样的结果。

总结

本文通过模拟非常简单的管道在go中实现的例子,解释了go语言中匿名管道的使用方式,当然和unix/c一样,go也支持命名管道,通过os.Pipe()即可轻松实现,基本原理均类似,在此不再赘述。

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!希望你也加入到我们人工智能的队伍中来!https://www.cnblogs.com/captainbed

原文地址:https://www.cnblogs.com/firsttry/p/10159917.html

时间: 2024-10-28 18:52:59

go语言快速入门 IPC之管道通信 8的相关文章

go语言快速入门 IPC之Socket 9

多进程之间的通信常见的手段有管道/信号量/共享内存/Socket等,在上篇文章中介绍了管道的使用方法.管道在多进程通信中使用方便但是也具局限性,当通信双方在不同的机器上的时候通信方式更多采用Socket方式.在这篇文章中我们将会继续探索如何使用go所提供的net包等实现TCP和UDP方式的Socket通信. 传输层协议 OSI模型 OSI七层模型,简单来说,下三层主要负责数据通信,而上三层主要负责数据处理.处于第四层的传输层是通信子网和资源子网的接口和桥梁,整体起到承上启下的作用.而TCP和UD

C语言快速入门系列(六)

C语言快速入门系列(五) C语言指针加强 本节引言: 上一节我们对C语言中的指针进行了初步的了解,学习了指针的定义,与普通变量 一维数组,二维数组,字符串之间的使用!在本节中我们将会学习一些新的知识点, 函数,结构体与共用体,枚举类型以及类型定义符typedef! 本节学习路线图: 本节正文 函数 ps:空函数就是什么都不做的函数,开发过程中不需要马上实现的,先写空函数!简单的空函数:void abc(){   } 结构体 共用体: 代码示例2: 建立一个共用体类型,当输入的时学生类型时,要求输

C语言快速入门教程(二)

C语言快速入门教程(二) C语言的基本语法 本节学习路线图: 引言: C语言,顾名思义就是一门语言,可以类比一下英语; 你要说出一个英语的句子需要:  单词  +  语法!  将单词按照一定的语法拼凑起来就成了一个英语句子了; C语言同样是这样,只不过单词可以理解为一些固定的知识点,而语法可以理解为算法(可以理解为解决问题的方法) 在这一节中我们就对固定知识点中的语言描述与数据存储进行解析! 1.C语言的基本元素 1.1  标识符 什么是标识符? 答:在C语言中,符号常量,变量,数组,函数等都需

C语言快速入门系列(一)

C语言快速入门系列(一)  本系列引言: 本教程的宗旨是将C语言入门的内容进行关键知识点的提纯,将一些笼统的废话去除; 再进行压缩,然后将本章的关键知识点做成路线图的,可以更加方便地掌握学习的方向; 最后提供相关的代码示例以及详细注释,可以帮助学者更快地上手C语言! 如果对本教程有什么建议和缺点纰漏的,欢迎指出,不胜感激! 本节学习路线图: 正文: 1.计算机与程序设计语言的关系: 答:计算机是由硬件与软件系统组成,硬件==>物质基础;软件==>灵魂; 如果脱离了软件,计算机就只是一台什么都做

C语言快速入门教程(一)

C语言快速入门教程(一) C语言概述(开发准备) 本节学习路线图: ps:标记3的表示不是很重要,知道有这个东西就行了;标记1表示非常重要,需要熟练掌握! 1.C语言的概述: 1.1  计算机与程序设计语言之间的关系? 答:计算机是由硬件与软件系统组成的;硬件---->物质基础;软件----->灵魂; 如果脱离了软件,计算机就是一台什么都做不了的裸机; 可以形象地比喻成人的大脑和身体;两个互不可缺! 1.2  程序设计语言的更新换代: 1.3 C语言的特点 1.4  最简单的HelloWorl

C语言快速入门系列(五)

C语言快速入门系列(五) C语言指针初涉                                           ------转载请注明出处:coder-pig 本节引言: 上一节我们对C语言复合数据类型中的数组进行了解析,在本节中,我们会对C语言复合数据类型中的 重点,C语言的灵魂-----指针进行学习!使用指针的好处:利用指针可以表示与使用复杂的数据结构; 更加方便地使用我们的数组与字符串;可以像汇编语言一样直接处理内存单元地址;可以动态地进行内存空间 分配,C语言指针是重点,同

Swift语言快速入门

Swift语言快速入门(首部同步新版官方API文档和语法的Swift图书,确保代码可编译,作者专家在线答疑,图书勘误实时跟进) 极客学院 编著   ISBN 978-7-121-24328-8 2014年10月出版 定价:59.00元 428页 16开 编辑推荐 本书内容翔实,实例丰富,同步新版官方API文档和语法 语法|词法|框架覆盖全面,实战案例|配套习题丰富 多位Swift专家联合推荐,不仅是Swift入门书籍,也可做案头工具书 作者携手Swift专家在线答疑,方式如下: 1.专属勘误交流

C语言快速入门系列(九)

C语言快速入门系列(九)                                               ---转载请注明出处:coder-pig C语言知识点拾遗 本节引言: C语言系列已经接近尾声了,在前面八节的学习中,我们学会了C的基本语法,基本数据类型, 三种程序结构(顺序,判断,循环),数组,函数,指针,结构体,共用体,位运算,文件等内容, 本节将对前面没有讲的C的遗漏知识点进行补充,当然发现有那些的遗漏的知识点也会进行更新! 谢谢大家一直以来的支持,说了这么多的理论,缺的

C语言快速入门系列(七)

C语言快速入门系列(七) C语言指针进阶 本章引言: 在前面第5节中我们对C语言的指针进行了初步的学习理解;作为C语言的灵魂, C指针肯定没那么简单,在这一节中,我们将会对指针进行进一步的学习,比如二级指针, 指针数组,内存分配和const修饰指针常量等!下面就请大家跟随笔者的脚步,对 C指针神秘的一面进行进一步的解析吧! 本节学习路线图: 函数与指针: ①指针作为函数的形参: ②指向函数的指针: ③指针函数: ④带参数的主函数 ps:该代码的运行:先要编译生成exe文件后,来到exe所在文件目