开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
进程间通信(IPC,Inter-Process Communication)
进程是计算机系统分配资源的最小单位。每个进程都有自己的一部分独立的系统资源,彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作,才有了进程间通信。进程间通信技术包括消息传递、同步、共享内存和远程过程调用。IPC分为LPC和RPC
LPC和RPC
本地过程调用(LPC)LPC用在多任务操作系统中,使得同时运行的任务能互相会话。这些任务共享内存空间使任务同步和互相发送信息。
远程过程调用(RPC)类似于LPC,只是在网上工作。同一主机中由于有函数栈的存在,调用函数时直接将现场压栈,将函数参数压栈,然后PC跳到目的地址执行函数,执行完后PC根据栈中的数据调回到原来的地方。但是进程分布在不同主机时,就不能这样做了,需要用到RPC。
RPC
在分布式计算, **远程过程调用**(英语:Remote Procedure Call,缩写为 RPC)是一个计算机通信
协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的
子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC 是一
种服务器-客户端( Client/Server )模式,经典实现是一个通过 **发送请求-接受回应** 进行信息交
互的系统。
来源:wiki 维基百科
RPC的组成
一个完整的RPC框架,无论是genrpc、grpc还是net/rpc,都需要有这四种组件:
- client端:服务的调用方,一般通过client.Call函数远程调用
- server端:服务的提供者
- client stub:客户端存根,它会存放服务端的地址,client发送请求时会将请求参数和服务器地址打包成网络信息,然后发给server。
- server stub:服务端存根,接受client发来的消息,解包,根据参数调用server本地的方法,会将结果返回到client。
简单的Go RPC服务(调用远程向量加法器)
任务要求:客户端传入向量参数,发送给服务端,服务端计算完后返回给客户端,客户端显示结果
文件目录如下:
-RPC Calculate
-client
-client.go
-go.mod
-server
-common_server
-common.go
-server.go
-go.mod
注意首先创建目录,然后分别在server和client文件夹下调用命令行
go mod init server //server文件夹下调用
go mod init client //client文件夹下调用
运行上面两行命令后会各自生成go.mod文件,这是一个包管理文件。
common.go
package common_server
import "errors"
type Args struct {
A, B []int32
}
type Result struct {
C []int32
}
type VectorServer struct{}
func (t *VectorServer) Add(args *Args, reply *Result) error {
if len(args.A) != len(args.B) {
return errors.New("Vector lengths do not match")
}
reply.C = make([]int32, len(args.A))
for i := 0; i < len(args.A); i++ {
reply.C[i] = args.A[i] + args.B[i]
}
return nil
}
server.go
package main
import (
"Server/common_server"
"fmt"
"net/http"
"net/rpc"
)
func main() {
var ms = new(common_server.VectorServer) // create a new VectorServer
var err = rpc.Register(ms)
if err != nil {
fmt.Println("rpc.Register failed:", err)
return
}
rpc.HandleHTTP()
// start listening for incoming connections
fmt.Println("Listening on port 9090...")
err = http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println("ListenAndServe failed:", err)
}
fmt.Println("Server stopped....")
}
client.go
package main
import (
"fmt"
"log"
"net/rpc"
)
type Args struct {
A, B []int32
}
type Result struct {
C []int32
}
func main() {
args := Args{A: []int32{1, 2, 3}, B: []int32{4, 5, 6}}
reply := Result{}
client, err := rpc.DialHTTP("tcp", "localhost:9090")
if err != nil {
log.Fatal("Dialing:", err)
}
err = client.Call("VectorServer.Add", &args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Result: %v", reply.C)
}
在server和client下分别开一个终端 注意先运行server再运行client
- server下
go run .
- client下
go run .
server端显示:
Listening on port 9090...
client端显示:
Result: [5 7 9]