Go学习笔记—基于Go的进程间通信

IPC(Inter-Process Communication 进程间通信)

一般方法:(1) 半双工Unix管道 (2) FIFOs(命名管道) (3) 消息队列 (4) 信号量 (5) 共享内存 (6) 网络Socket (7) RPC(远程过程调用)

(一)管道(Pipe)

1.未命名管道(ps aux | grep java)
cmd1 := exec.Command("ps", "aux")
cmd2 := exec.Command("grep", "apipe")//cmd对象的底层,Stdout与Stdin属性也是通过指向一个字节流实现读写的,这里用新建的字节流代替
var outputBuf1 bytes.Buffer
cmd1.Stdout = &outputBuf1
if err := cmd1.Start(); err != nil {fmt.Printf("Error: The first command can not be startup %s\n", err)return
}
if err := cmd1.Wait(); err != nil {		//wait会阻塞cmd直到其运行完毕fmt.Printf("Error: Couldn't wait for the first command: %s\n", err)return
}
//cmd1的输出与cmd2的输入指向同一个字节流地址
cmd2.Stdin = &outputBuf1
var outputBuf2 bytes.Buffer
cmd2.Stdout = &outputBuf2
if err := cmd2.Start(); err != nil {fmt.Printf("Error: The second command can not be startup: %s\n", err)return
}
if err := cmd2.Wait(); err != nil {fmt.Printf("Error: Couldn't wait for the second command: %s\n", err)return
}
2.命名管道(mkfifo -m 777 myfifo cat src.log > myfifo)
操作作用特性
reader, writer, err := os.Pipe()创建独立管道可以被多路复用,不提供原子操作支持
reader, writer, err := os.Pipe()
if err != nil {fmt.Printf("Error: Couldn't create the named pipe: %s\n", err)
}
//Read与Write会在另一端还未就绪时对进程进行阻塞,所以二者需要并发运行
go func() {output := make([]byte, 100)n, err := reader.Read(output)if err != nil {fmt.Printf("Error: Couldn't read data from the named pipe: %s\n", err)}fmt.Printf("Read %d byte(s). [file-based pipe]\n", n)
}()
input := make([]byte, 26)
for i := 65; i <= 90; i++ {input[i-65] = byte(i)
}
n, err := writer.Write(input)
if err != nil {fmt.Printf("Error: Couldn't write data to the named pipe: %s\n", err)
}
fmt.Printf("Written %d byte(s). [file-based pipe]\n", n)
操作作用特性
reader, writer := io.Pipe()创建内存独立管道基于内存的提供原子操作保证的管道
reader, writer := io.Pipe()
go func() {output := make([]byte, 100)n, err := reader.Read(output)if err != nil {fmt.Printf("Error: Couldn't read data from the named pipe: %s\n", err)}fmt.Printf("Read %d byte(s). [in-memory pipe]\n", n)
}()
input := make([]byte, 26)
for i := 65; i <= 90; i++ {input[i-65] = byte(i)
}
n, err := writer.Write(input)
if err != nil {fmt.Printf("Error: Couldn't write data to the named pipe: %s\n", err)
}
fmt.Printf("Written %d byte(s). [in-memory pipe]\n", n)
time.Sleep(200 * time.Millisecond)

(二)信号(Signal)

​ IPC中唯一一种异步通信方法,本质是利用软件来模拟硬件的中断机制,信号用来通知某个进程有某个事件发生了。

​ Linux中一共有62种信号,1到31属于标准信号,标准信号只会被处理并记录一次,并且一次发送的多个标准信号,其处理顺序是不确定的;34到64属于实时信号,多个同种类的实时信号都可以记录在案,并且可以按照信号的发送顺序被处理。(Ctrl—C == SIGINT)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3UGR24Z-1638325000547)(…/…/Pic/image-20211124160241715.png)]

type Signal interface{String() stringSignal()
}
方法作用
func Notify(c chan<- os.Signal, sig …os.Signal)当操作系统向当前进程发送指定信号时发出通知
func Stop(c chan<- os.Signal)删除定义的自处理通知通道,恢复系统默认操作
func FindProcess(pid int) (*Process, error)根据Pid返回一个进程对象,可以向对象发送Signal信息
syscall.SIGINT…syscall中定义了所有信号常量

os.Signal通道内部维护了一个包级私有字典,用于存放以Signal接收通道为键并以信号集合为元素的键—元素对。调用Notify函数时,若键—元素对不存在,则会向字典中添加一个,否则就更新其元素集合(仅能扩大);调用Stop函数时,将删除该键—元素对。

/**1. Notify不会因为sigRecv1满而被阻塞2. 接收到信号而不做合适的处理,相当于程序忽略掉了系统发来的信号3. SIGKILL和SIGSTOP永远不会被自处理或者忽略(因为他们是提供给超级用户终止或停止进程的可靠方法)即使Notify(,syscall.SIGKILL, syscall.SIGSTOP)也不会改变系统的处理动作
*/
//同一个进程可以建立多个自定义信号处理通道
sigRecv1 := make(chan os.Signal, 1)		
sigs1 := []os.Signal{syscall.SIGINT, syscall.SIGQUIT}
fmt.Printf("Set notification for %s... [sigRecv1]\n", sigs1)sigRecv2 := make(chan os.Signal, 1)
sigs2 := []os.Signal{syscall.SIGQUIT}
fmt.Printf("Set notification for %s... [sigRecv2]\n", sigs2)
// arg1:监测到信号时由此通知  arg2:监测的信号类型(不填则监控所有类型)
signal.Notify(sigRecv1, sigs1...)
signal.Notify(sigRecv2, sigs2...)
// 删除sigRecv1,之后恢复以系统默认方式处理信号
signal.Stop(sigRecv1)
//此时只剩下sigRecv2还在工作

(三)套接字(Socket)

​ 通过网络连接让多个进程建立通信并相互传递数据,实现进程跨机器通信。socket本身并不是一个协议,它只是提供了一个针对TCP或者UDP编程的接口,即是对TCP/IP协议的封装。

一、三种协议
  • TCP(Transmission Control Protocol 传输控制协议)

    ​ TCP是面向连接的、可靠的流协议。流就是指不间断的数据结构。TCP为提供可靠性传输,实行“顺序控制”或“重发控制”机制。此外还具备“流控制(流量控制)”、“拥塞控制”、提高网络利用率等众多功能。 此外,TCP作为一种面向有连接的协议,只有在确认通信对端存在才会发送数据,从而可以控制通信流量的浪费。

  • UDP(User Datagram Protocol 用户数据报协议)

    ​ UDP是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。在UDP的情况下,虽然可以确保发送信息的大小,却不能保证信息一定会到达。因此,应用有时会根据自己的需要进行重发处理。 UDP不提供复杂的控制机制,利用IP提供面向无连接的通信服务。由于UDP面向无连接,它可以随时发送数据。

  • SCTP(Stream Control Transmission Protocol 流控制传输协议)

    ​ SCTP是面向消息的(message-oriented)协议。同时也是面向连接、端到端、全双工、带有流量和拥塞控制的可靠传输协议。SCTP的连接称为关联,通过4次握手建立。SCTP能给在所连接的端点之间提供多个流,每个流各自可靠地按序递送消息。一个流上某个消息的丢失不会阻塞同一关联其他流上消息的投递。

    ——TCP VS UDP

    ​ 两者的区别在于TCP接收的是一堆数据,而每次取多少由主机决定;而UDP发的是数据报,客户发送多少就接收多少。

    ​ 拥有这些区别的原因是由于TCP和UDP的特性不同而决定的。TCP是面向连接的,也就是说,在连接持续的过程中,socket中收到的数据都是由同一台主机发出的,因此,知道保证数据是有序的到达就行了,至于每次读取多少数据自己看着办。 而UDP是无连接的协议,也就是说,只要知道接收端的IP和端口,且网络是可达的,任何主机都可以向接收端发送数据。这时候,如果一次能读取超过一个报文的数据,则会乱套。比如,主机A向发送了报文P1,主机B发送了报文P2,如果能够读取超过一个报文的数据,那么就会将P1和P2的数据合并在了一起,这样的数据是没有意义的。

    ——TCP VS SCTP

    (1)TCP是以字节为单位传输的,SCTP是以数据块为单位传输的

    ​ TCP接收端确认的是收到的字节数,SCTP接收端确认的是接收到的数据块。

    ​ 在实际的应用中,TCP发送方的可以将应用程序需要发送的多个消息打包到一个TCP包里面发出去。接收端在收到这个TCP包时,回给对端的ACK只是表明自己接收到了多少个字节,TCP协议本身并不会把收到的数据重新拆散分成两条应用层消息并通知应用程序去接收。应用需要根据应用程序自己定义的格式去拆成两条消息。与TCP不同,SCTP是将应用程序的每次调用sendmsg()发送的数据当作一个整体,放到一个被称为DATA CHUNK的数据块里面,接收端也是以DATA CHUNK为单位接收数据,并重新组包,通知应用程序接收。通常,应用程序每次调用recvmesg()都会收到一条完整的消息。

    (2)TCP通常是单路径传输,SCTP可以多路径传输

    ​ TCP的两端都只能用一个IP来建立连接,连接建立之后就只能用这一对IP来相互收发消息了。如果这一对IP之间的路径出了问题,那这条TCP连接就不可用了。SCTP两端都可以绑定到多个IP上,只要有其中一对IP能通,这条SCTP连接就还可以用。体现在socket API中,TCP只能bind一个IP,而SCTP可以bind到多个IP。

    (3)TCP是单流有序传输,SCTP可以多流独立有序/无序传输

    ​ 一条SCTP连接里面,可以区分多条不同的流(stream),不同的流之间的数据传输互不干扰。在同一条stream里面,SCTP支持有序/无序两种传输方式,应用程序在调用sendmsg()的时候,需要指定用哪一条stream传输,以及指定这条要发送的消息是需要有序传输还是无序传输的。如果在传输过程中丢包,则有序传递模式可能会在接收端被阻塞,而无序传输模式不会在接收端被阻塞。

    (4)TCP连接的建立过程需要三步握手,SCTP连接的建立过程需要四步握手

    ​ TCP连接建立过程,容易受到DoS攻击。在建立连接的时候,client端需要发送SYN给server端,server端需要将这些连接请求缓存下来。通过这种机制,攻击者可以发送大量伪造的SYN包到一个server端,导致server端耗尽内存来缓存这些连接请求,最终无法服务。

    ​ SCTP的建立过程需要四步握手,server端在收到连接请求时,不会立即分配内存缓存起来,而是返回一个COOKIE。client端需要回送这个COOKIE,server端校验之后,从cookie中重新获取有效信息(比如对端地址列表),才会最终建立这条连接。这样,可以避免类似TCP的SYN攻击。

    (5)SCTP有heartbeat机制来管理路径的可用性

    ​ SCTP协议本身有heartbeat机制来监控连接/路径的可用性。SCTP两端都可以bind多个IP,因此同一条SCTP连接的数据可以采用不同的IP来传输。不同的IP传输路径对应一条path,不同的path都可以由heartbeat或者是数据的传输/确认来监控其状态。如果heartbeat没相应,或者是数据在某条path超时没收到确认导致重传,则认为该path有一次传输失败。如果一条连接的连续传输次数超过设定的“连接最大重传次数”,则该连接被认为不可用,该连接会被关闭并通知应用程序。

二、socket基本特性
1. 通信域:
通信域含义地址形式通信范围
AF_INETIPV4域地址4字节 端口2字节IPV4网络下两台计算机间的应用程序
AF_INET6IPV6域地址16字节 端口2字节IPV6网络下两台计算机间的应用程序
AF_UNIXUnix域路径名称同一计算机下的两个应用程序
2. socket类型:
特性SOCK_DGRAMSOCK_RAWSOCK_SEQPACKETSOCK_STREAM
数据形式数据报数据报字节流字节流
数据边界没有没有
逻辑连接没有没有
数据有序性不能保证不能保证能保证能保证
传输可靠性不具备不具备具备具备
3. socket通信过程:
  • 创建socket实例 socket() .
  • (客户端)绑定本机地址 bind() ######(服务器)创建socket实例、绑定本机地址 bind()、在地址上监听 listen()
  • 连接服务器 connect() ———————请求并建立TCP连接———————> >等待连接接入 accept()
  • 发送数据 write() ———————— 数据(请求) —————————> >接收数据 read()
  • 接受数据 read() <——————— 数据(响应) —————————— >发送数据 write()
  • 关闭连接 close() ———————— 文件结束通知 ———————-> >接收数据 read() 关闭连接 close()
4. Go API实现

​ Go底层获取的是操作系统的非阻塞式socket实例,即read()与write()不会阻塞程序运行。

部分读:即调用read()时,即使缓冲区没有任何数据,操作系统不会阻塞该系统调用,而是直接返回一个错误码EAGAIN,应用程序应该忽略他并在稍后再次尝试读取;在缓冲区有数据时,无论有多少数据,都会立即读取该数据并返回。

部分写:即调用write()时,即使缓冲区已满,操作系统不会阻塞该系统调用,而是直接返回一个错误码EAGAIN,应用程序应该忽略他并在稍后再次尝试写入;在缓冲区有部分空间时,无论是否可以全部写入,都会尽可能写入部分数据并返回写入的数据量。

​ Go帮我们屏蔽了系统的EAGAIN错误,屏蔽了其部分写特性,而保留了部分读特性(由于TCP字节流传输,接收方无法感知数据边界,所以不能帮助我们屏蔽部分读特性)

方法作用
func Listen(net, laddr string) (Listener, error)获取监听器
func Accept()监听器开始接收请求
func Dial(network, address string) (Conn, error)向指定网络发送连接建立申请
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)申请连接并设定连接超时等待时间
func Read(b []byte) (n int, err error)从socket接收缓冲区读数据
func Write(b []byte) (n int, err error)向socket写入缓冲区写数据
func Close() (err error)关闭连接
func LocalAddr() net.Addr | func RemoteAddr() net.Addr获取当前连接的本地地址和远程地址
上面两方法的返回值可以调用两个方法:.String() 网络地址 .Network() 协议类型
func SetDeadline(time.Time) error | SetReadDeadline| SetWriteDeadline设置连接读、写超时时间
// 服务器端开启监听
listener, err := net.Listen("tcp", "127.0.0.1:8085")   //协议名 监听地址
conn, err := listener.Accept()// 客户端开启发送,注意:客户端可以不绑定本机地址,操作系统内核会为其分配一个
conn1, err := net.Dial("tcp", "127.0.0.1:8085")        //协议名 发送地址
conn2, err := net.DialTimeout("tcp", "127.0.0.1:8085", 2*time.Second)  //协议名 发送地址 TCP连接超时时间
//*************************************************************************************
//1.直接通过Buffer读取
var dataBuffer bytes.Buffer
b:=make([]byte, 10)
for{n, err := conn.Read(b)if err != nil{if err == io.EOF{		//发现TCP连接在另一端已经关闭conn.Close()}else{fmt.Printf("error:%s\n", err)}break}dataBuffer.Write(b[:n])
}
//2.通过bufio读取
reader := bufio.NewReader(conn)     
line, err := reader.ReadBytes('\n')
//3.通过bufio写入
writer := bufio.NewWriter(conn1)
//*************************************************************************************
conn.LocalAddr().String()     //获取网络地址
conn.LocalAddr().Network()    //获取协议类型
//*************************************************************************************
// SetDeadline设置的是一个绝对时间(即具体时间),并且会对以后的每次读写都生效
// 所以循环读写的操作,需要不断更新这个时间
b:=make([]byte, 10)
for{conn.SetDeadline(time.Now().Add(2*time.Second))n, err:=conn.Read(b)
}
conn.SetDeadline(time.Time{})	//取消超时时间设置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rsync+lsyncd实现(本地以及远程)文件实时同步

lsyncd基于lua语言开发&#xff0c;整合了rsync和notify 实现文件的实时同步 系统环境cat /etc/issue CentOS release 6.6 (Final)uname -sr Linux 2.6.32-504.el6.x86_64 服务器规划 rsync服务器&#xff1a; 192.168.10.241 rsync lsyncd服务器 &#xff…

萨蒂扬软件技术(南京)研发中心”落户高新区

萨蒂扬软件技术&#xff08;南京&#xff09;研发中心”落户高新区 2007-02-12“中国软件名城”成为南京吸引世界软件巨头强磁场“萨蒂扬软件技术&#xff08;南京&#xff09;研发中心”落户高新区 世界知名的印度软件企业巨头萨帝扬计算机服务有限公司挥师江苏亮出精彩第一笔…

JavaScript常用正则表达式收集

JavaScript常用正则表达式收集 ---------------------------------------------------------------------------------------- 正则的用法参见&#xff1a;http://blog.csdn.net/xxj_jing/article/details/6977078 下面是个简单判断 1.匹配中文字符 2.匹配特殊字符(符合 wind…

Go学习笔记—多线程

多线程编程 ​ 一个进程可以包含多个线程&#xff0c;这些线程运行的一定是同一个程序&#xff08;进程程序&#xff09;&#xff0c;且都由当前进程中已经存在的线程通过系统调用的方式创建出来。进程是资源分配的基本单位&#xff0c;线程是调度运行的基本单位&#xff0c;线…

maven必知必会

目录 了解mavenmaven的作用maven仓库本地配置添加远程仓库依赖搜索顺序定制包到本地仓库pom文件依赖管理原则构建声明周期插件了解maven maven的作用 maven采取约定大于配置的原则,规范了一套标准的javaweb项目结构maven提供了完备的包管理功能,不用到处找jar包了maven提供了一…

lecture 4 : More Objective-C

Creating Objects 这件事困扰我一点时间了&#xff0c;ObjC没有一个Constructor的概念 而在Create Objects这件事上既有用过自己写的-init&#xff0c;还return instancetype&#xff0c;大概这个&#xff0c;也有用过一些Class Method&#xff0c;就是明确知道是id类型的&…

对象实体 参考标准

1usingSystem;2usingSystem.Data;34namespaceFramework.Components5{ 6 /**//// <summary> 7 /// 公告通知实体 8 /// </summary> 9 public class NoticeInfo 10 { 11 基础信息-------------------------------------------------------…

SerialPort comstat is being used without defining

Run-Time Check Failure #3 - The variable comstat is being used without being initialized. 参考&#xff1a;http://blog.sina.com.cn/s/blog_5d2412000100ojx3.html 方案1: 改变项目配置属性 一种解决方案是改变基本运行时检查&#xff08;changing the runtime checks i…

Leetcode:27. 移除元素

力扣题目链接 解题思路 首先很容易想到暴力解法,用两个for循环,第一个for循环用来遍历整个数组,第二个for循环用来更新数组.但这种解法的时间复杂度为O(n^2) 因此考虑双指针思想,通过一个快指针和慢指针在一个for循环下完成两个for循环的任务,其中,快指针用来寻找新的元素,即…

【原】简单shell练习(四)

1.查看已开启端口信息 #ss -ln 2.列出谁在使用某个端口&#xff08;如&#xff1a;80&#xff09; #lsof -i:80 3.显示文件夹下文件信息 #find /home/root -type f#find -type f 4.磁盘大小信息 #df -h #du -sh * 5.查看一个文件夹下文件总个数 # ls -l |wc -l 6.查看进程是否…

JavaScriptWindow使用对象

窗口对象的属性和方法&#xff1a;格式&#xff1a;[window.]属性[window.]方法&#xff08;参数&#xff09;opener.属性opener.方法&#xff08;参数&#xff09;self.属性self.方法&#xff08;参数&#xff09;parent.属性parent.方法&#xff08;参数&#xff09;top.属性…

无法在web服务器上启动调试 您不具备调试此应用程序的权限

一般用下面的方法可以解决: 1&#xff1a;确认在“配置属性”中的“启用ASP.NET调试"为"True" 2&#xff1a;确认你的"web.config"中的"debugtrue" 3&#xff1a;若你安装过Win2000 SP4后&#xff0c;则要在命令行执行"regsvr32 i asp…

Go学习笔记—Go并发基础

Go并发基础 并行&#xff1a;程序在任意时刻内都是同时运行的 并发&#xff1a;程序在单位时间内都是同时运行的 ​扇入&#xff1a;多条通道聚合到一条通道中&#xff08;select聚合&#xff0c;加密解密服务&#xff09; ​扇出&#xff1a;一条通道发散到多条通道中&#x…

史蒂夫乔布斯6月斯坦佛大学演讲: 必须找到你所钟爱的东西

博客搬家咯&#xff5e; http://joeleee.github.io/ 博客搬家咯&#xff5e; http://joeleee.github.io/ 博客搬家咯&#xff5e; http://joeleee.github.io/ 关于如何将生命中的点点滴滴串联起来&#xff0c;关于爱和损失&#xff0c;关于死亡&#xff0c;乔布斯如是说. h1 ! …

博客园贵团队可以给个解释么?

发表了一片文章&#xff0c;被博客园团队移除出首页&#xff0c;自认为没有违反规定&#xff0c;于是回复该消息&#xff0c;想询问原因&#xff0c;但是一直没得到回复&#xff0c;请问这是为什么呢&#xff0c; 为什么那么久了还是未读状态&#xff0c;为什么从来不给回复&am…

unity, 颜色随高度渐变shader

一&#xff0c;颜色随世界空间高度渐变。 Shader "Custom/heightGradual_worldSpace" { Properties { _Color ("Color", Color) (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) "white" {} _Glossiness ("S…

WinForm给ComboBox增加Value(转)

做一个图书管理系统,用到了combobox, 天呀,竟然不能像DropDownList那样直接使用键值对的方式 百度了半天,终于找到方法,发出来大家共享 用DataTable可以&#xff01;但是总不能象男&#xff0c;女这样两项也用一个DataTable吧&#xff0c; 这也太麻烦了啊&#xff01; 用Hashta…

Go学习笔记—Channel通道

Go并发通信——Channel ​ Go语言的并发模型是CSP&#xff08;Communicating Sequential Processes&#xff09;&#xff0c;提倡通过通信共享内存而不是通过共享内存而实现通信。&#xff08;DO NOT COMMUNICATE BY SHARING MEMORY; INSTEAD, SHARE MEMORY BY COMMUNICATING.…

【转载】程序员技术练级攻略

月光博客6月12日发表了《写给新手程序员的一封信》&#xff0c;翻译自《An open letter to those who want to start programming》&#xff0c;我的朋友&#xff08;他在本站的id是Mailper&#xff09;告诉我&#xff0c;他希望在酷壳上看到一篇更具操作性的文章。因为他也是喜…

FileSystemObject (FSO)对象方法总结及应用

FileSystemObject (FSO)组件可以用来处理系统驱动器&#xff0c;文件夹&#xff0c;和文件。因为它是一个ActiveX控件&#xff0c;所以它能被js&#xff0c;vbs等文件使用&#xff0c;以实现对机器文件系统的操作。 下面将总结一下FSO中的对象和方法&#xff0c;其实FSO中大多数…