RPC definition, from Baidu Encyclopedia
RPC (remote Procedure Call)-an agreement that requests a service from a remote computer program over a network without needing to know the underlying network technology. The RPC protocol assumes that some transport protocols exist, such as TCP or UDP, to carry information data between communication programs. In the OSI network communication model, RPC spans the transport and application tiers. RPC makes it easier to develop applications that include distributed, multi-program networks.
RPC takes client/server mode. The requestor is a client, and the service provider is a server. First, the client call process sends a call message with process parameters to the service process, and then waits for the reply message. On the server side, the process stays asleep until the call information arrives. When a call arrives, the server obtains the process parameters, evaluates the result, sends a reply message, and then waits for the next invocation information, and finally, the client invokes the process to receive the reply message, obtains the process result, and then invokes execution to proceed.
There are multiple RPC modes and executions. Originally presented by Sun Corporation. The IETF ONC charter re-revised the Sun version, making the ONC RPC protocol an IETF standard protocol. Now using the most common patterns and execution is an open software-based distributed computing Environment (DCE).
Personal understanding: Do not care what the underlying network technology protocol, is a network from the computer program to request services, popular point, we write code, in a place, such as Android, you need to be in a project inside, can call to other program code execution process. The Go language provides RPC support to enable applications that develop network-distributed programs toeasy
RPC Workflow Flowchart
Images from GitHub
- 1. Invoking the client handle; executing the transfer parameters
- 2. Call the local system kernel to send a network message
- 3. Messaging to a remote host
- 4. Server handle get message and get parameters
- 5. Performing a remote procedure
- 6. The execution process returns the result to the server handle
- 7. Server handle returns result, call remote system kernel
- 8. Send the message back to the local host
- 9. Client handles receive messages from the kernel
- 10. The customer receives the data returned by the handle
The Go language provides support for RPC: HTTP、TCP、JSPNRPC
but Go
RPC
it is unique in that it uses GoLang Gob
encoding and can only support the go language!
- Golang Gob: is a data structure serialized encoding/decoding tool with Golang package. Encoding uses encoder, decoding uses decoder. A typical application scenario is RPC (remote procedure calls).
HTTP RPC Demo
Package Mainimport ("FMT" "Net/rpc" "Net/http" "errors") func main () {Rpcdemo ()}type arith intfunc Rpcdem O () {arith:=new (arith)//arith=== 0xc04204e090 FMT. Println ("arith===", Arith) RPC. Register (Arith)//handlehttp the HTTP handler for the RPC message to the debug handler on the Debug server//defautupcpath and debug debug path. HTTP still needs to be called. Services (), usually in a go statement. Rpc. Handlehttp () err:=http. Listenandserve (": 1234", nil) if err! = Nil {fmt. Println ("err=====", err. Error ())}}type Args struct {A, B int}type quotient struct {Quo, Rem int}//function must be exported (capitalized)//must have two parameters for export type,//First parameter The number is the received parameter, the second parameter is the parameter returned to the client, the second argument must be a pointer type//function and a return value of Errorfunc (t *arith) Multiply (args *args, reply *int) error {*reply = Args. A * args. FMT B. Println ("This method executes AH---hehe---Multiply", reply) return Nil}func (t *arith) Divide (args *args, quo *quotient) error {if Args. B = = 0 {return errors. New ("Divide by Zero")} quo. Quo = args. A/args. B Quo. Rem = args. A% args. FMT B. Println ("This method has been executed---Hehe---Divide quo== ", quo) return nil}
- The function of Go RPC can be accessed remotely only if it meets four criteria, otherwise it will be ignored
- The function must be capitalized (can be exported)
- Must have two parameters for the exported type
- The first parameter is the accepted argument, the second argument is the parameter returned to the client, and the second argument is the type of the pointer
- Function must also have a return value
error
func (t *T) MethodName(argType T1, replyType *T2) error
Package Mainimport ("Log" "FMT" "OS" "Net/rpc" "StrConv") type argstwo struct {A, B int}type QUOTIENTTW o struct {Quo, Rem Int}func Main () {//If nothing is entered, it is the following value//os***************** [C:\Users\win7\AppData\Local\ temp\go-build669605574\command-//line-arguments\_obj\exe\gorpcweb.exe 127.0.0.1] ********************** fmt. Println ("os*****************", OS. Args, "**********************") If Len (OS. Args)! = 4 {//TODO the second address is our local address FMT. Println ("Lao Tzu to Quit Oh, the first start--------" ", OS.) Args[0], "---------------server End") OS. Exit (1)}else{FMT. Println ("Length is how much" +strconv. Itoa (len (OS). Args) + "is the exact length oh---")}//Gets the input address is the value of the first location to get input OS data serveraddress: = OS. ARGS[1] FMT. Println ("severaddress==", serveraddress)////delayhttp is connected to the HTTP RPC server at the specified network address///listening on the default HTTP RPC path. Client, err: = RPC. Dialhttp ("TCP", serveraddress) if err! = Nil {log. Fatal ("Error has occurred here in place Dialhttp", err)} i1,_:=strconv. Atoi(OS. ARGS[2]) I2,_:=strconv. Atoi (OS. Args[3]) Args: = Argstwo{i1, i2} var reply int//Call Call the named function, wait for it to complete, and return its error state. Err = client. Call ("Arith.multiply", args, &reply) if err! = Nil {log. Fatal ("Call Multiply error has occurred oh Arith error:", err)} FMT. Printf ("Arith multiplication:%d*%d=%d\n", args. A, args. B, Reply) var quot quotienttwo//Call the named function, wait for it to complete, and return its error state. Err = client. Call ("Arith.divide", args, ") if err! = Nil {log. Fatal ("Arith error:", err)} FMT. Printf ("Arith Division takes integers:%d/%d=%d remainder%d\n", args. A, args. B, quot. Quo, quot. REM)}
Run a result diagram
E:\new_code\GoDemo\web_server>go run GoRPCWeb8.go 127.0.0.1:1234 20 3os***************** [C:\Users\win7\AppData\Local\Temp\go-build011170718\command-line-arguments\_obj\exe\GoRPCWeb8.exe 127.0.0.1:1234 20 3] **********************长度是多少 4才是准确的长度 哦---》severAddress== 127.0.0.1:1234Arith 乘法: 20*3=60Arith 除法取整数: 20/3=6 余数 2
- Go run gorpcweb8.go 127.0.0.1:1234 20 3
- Commands run by Go run
- Gorpcweb8.go: This is the name of the file and needs to be started in the specified directory
cmd
- 127.0.0.1:1234:IP Address and port number
- 20 3 This is the customer service. The value passed in: a divisor, a divisor, incoming to the server multiplication multiplication:
20*3=60
and division take integer: 20/3=6
remainder 2
, how to do, the client does not care, to the service side to complete
os.Args[0]
=[C:\Users\win7\AppData\Local\Temp\go-build011170718\command- line-arguments\_obj\exe\GoRPCWeb8.exe 127.0.0.1:1234 20 3]
if len(os.Args) != 4 { // todo 第二个地址是 我们本地的地址 fmt.Println("老子要退出了哦 傻逼 一号start--------》》》", os.Args[0], "《《《---------------server end") os.Exit(1) }else{ fmt.Println("长度是多少 "+strconv.Itoa( len(os.Args))+"才是准确的长度 哦---》") }
TCP RPC Demo
- RPC, server-side code implementation based on TCP protocol
Package Mainimport ("FMT" "Net/rpc" "NET" "OS" "Errors") Func init () {FMT. Println ("RPC based on TCP protocol, service-side code is as follows")}type Me struct {A, b int}type you struct {cc,d int}type Num int/*go RPC function only conforms to the following The condition can be accessed remotely, otherwise it will be ignored 1 function must be exported (first letter uppercase) 2 must have two export type parameter 3 The first parameter is an accepted parameter, the second parameter is the parameter returned to the client, the second argument must be of type 4 function must also have a return value error */ Func (n *num) M (args *me,reply *int) error {*reply=args. A * args. B return Nil}func (n *num) F (args * me,u *you) error {if args. b==0{return errors. New ("Input cannot be 0 dividend")} U.d=args. A/args. B U.cc=args. A% args. B return Nil}func Main () {///the built-in function new is essentially the same as the function of the same name in other languages: new (T) allocates a memory space of type T with a value of 0, and returns its address, which is the value of a *t type. In the terms of go, it returns a pointer to the 0 value of the newly assigned type T. One thing is very important://new returns a pointer. Num:=new (Num) RPC. Register (num)//resolvetcpaddr returns the address of the TCP endpoint. The network must be a TCP network name. Tcpaddr,err:=net. RESOLVETCPADDR ("TCP", ": 1234") if err! = Nil {fmt. Println ("Wrong Oh") os. Exit (1)} listener,err:=net. LISTENTCP ("TCP", tcpaddr) for {//TODO requiredTo control the connection yourself, we need to give the connection to RPC to handle the Conn,err:=listener when there is a client connection. Accept () if err! = nil {continue} RPC. SERVECONN (conn)}}
Package Mainimport ("FMT" "OS" "Net/rpc" "Log" "StrConv") func main () {FMT. Println ("The other side of the client to call where the corresponding example is Gotcprpc9.go") If Len (OS. Args) ==4{FMT. PRINTLN ("Length must be equal to 4, because what you enter is definitely an IP address ip=", OS. Args[1], "hehe, plus the back of the dividend OS. Args[2]= ", Os. ARGS[2], "and the divisor OS. Args[3]= ", Os. ARGS[3])//os. Exit (1)}//Get IP address service:= os. ARGS[1]//Connect a dial-up connection to the specified network address of the RPC server. Client,err:=rpc. Dial ("TCP", service) if Err!=nil {log. Fatal ("I am in connection with dial error, I want to quit", err)} num1:=os. ARGS[2] I1,error1:=strconv. Atoi (NUM1) if Error1!=nil {fmt. Println ("I don't know if I entered the wrong one, see error:", Error1) os. Exit (1)} num2:=os. ARGS[3] I2,error2:=strconv. Atoi (num2) if Error2!=nil {fmt. Println ("I don't know if I entered the wrong one, see error:", Error2) os. Exit (1)} Aa:=aaa{i1,i2} var reply int err1:=client. Call ("NUM.M", aa,&reply) if err1! = nil{log. Fatal ("I'm quitting because I had an error at call", ERR1)} fmt. PRINTLN ("I conduct normal results as follows") FMT. Printf ("Num:%d*%d=%d\n ", AA. A,aa. b,reply) var bb bdemo//calls the named function, waits for it to complete, and returns its error state. Err= client. Call ("NUM.F", AA,&BB) if Err!=nil {log. Fatal ("I reacted to this method of allergic reaction haha haha err=====", err)} FMT. Printf ("Num:%d/%d=%d remainder%d\n", AA. A,aa. B,bb. Dd,bb. CC)}//defines two classes, where the class that needs to be manipulated type AAA struct {A, B int}//remember there is no way to capitalize a two-letter together capitalization a little meaning//reading body gob:type mismatch:no Field s matched compiling decoder for dddd//todo Why the second parameter as long as it is two connected DDDD will be an error reading body Gob:type mismatch:no fields Matched compiling decoder fortype bdemo struct {DD, CC int}
Run the result diagram
Result diagram
E:\new_code\GoDemo\web_server>go run GoTCPRPCWeb10.go 127.0.0.1:1234 20 1客户端 其他端 去调用的地方 对应的例子是 GoTCPRPC9.go长度必须等于4,因为呢,你输入的肯定是一个ip的地址ip= 127.0.0.1:1234 嘿嘿,加上后面的被除数os.Args[2]= 20 和除数os.Args[3]= 1我进行正常结果如下Num : 20*1=20Num: 20/1=0 余数 0E:\new_code\GoDemo\web_server>go run GoTCPRPCWeb10.go 127.0.0.1:1234 20 2客户端 其他端 去调用的地方 对应的例子是 GoTCPRPC9.go长度必须等于4,因为呢,你输入的肯定是一个ip的地址ip= 127.0.0.1:1234 嘿嘿,加上后面的被除数os.Args[2]= 20 和除数os.Args[3]= 2我进行正常结果如下Num : 20*2=40Num: 20/2=0 余数 0E:\new_code\GoDemo\web_server>go run GoTCPRPCWeb10.go 127.0.0.1:1234 20 3客户端 其他端 去调用的地方 对应的例子是 GoTCPRPC9.go长度必须等于4,因为呢,你输入的肯定是一个ip的地址ip= 127.0.0.1:1234 嘿嘿,加上后面的被除数os.Args[2]= 20 和除数os.Args[3]= 3我进行正常结果如下Num : 20*3=60Num: 20/3=0 余数 2
- At the
BDemo
time of definition, if the definition DD, CC int
and the service side is not the same, will be error reading body gob: type mismatch: no fields matched compiling decoder for
, in fact, found a good variety of situations, will also appear this error, but at present do not know why this, follow-up, such as the source into a bit, come back to see this problem TODO2018/07/19
- The
TCP
difference between this way and the above HTTP
is that
- http: Specifies the network address to connect to the HTTP RPC server
//DelayHTTP在指定的网络地址连接到HTTP RPC服务器 ///在默认HTTP RPC路径上监听。 client, err := rpc.DialHTTP("tcp", serverAddress)
- TCP: Specifies the network address to connect to the HTTP RPC server
client,err:=rpc.Dial("tcp",service)
JSON RPC
JSON RPC
Is that the data is encoded using JSON
, rather than gob
coding, the others are identical to the concepts described above RPC
.
The service-side code is as follows
package mainimport ( "fmt" "net/rpc" "net" "net/rpc/jsonrpc")//使用Go提供的json-rpc 标准包func init() { fmt.Println("JSON RPC 采用了JSON,而不是 gob编码,和RPC概念一模一样,")}type Work struct { Who,DoWhat string}type DemoM stringfunc (m *DemoM) DoWork(w *Work,whoT *string) error { *whoT="是谁:"+w.Who+",在做什么---"+w.DoWhat return nil}func main() { str:=new(DemoM) rpc.Register(str) tcpAddr,err:=net.ResolveTCPAddr("tcp",":8080") if err!=nil{ fmt.Println("大哥发生错误了啊,请看错误 ResolveTCPAddr err=",err) } listener,err:=net.ListenTCP("tcp",tcpAddr) if err!=nil { fmt.Println("发生错误了--》err=",err) } for { conn,err:= listener.Accept() if err!=nil { continue } jsonrpc.ServeConn(conn) }}
package mainimport ( "fmt" "os" "net/rpc/jsonrpc" "log")func main() { fmt.Println("这是客户端,用来启动,通过命令行来启动") fmt.Println("客户端 其他端 去调用的地方 对应的例子是 GoTCPRPC9.go") if len(os.Args)==4{ fmt.Println("长度必须等于4,因为呢,你输入的肯定是一个ip的地址ip=",os.Args[1],"嘿嘿,加上后面的被除数os.Args[2]=",os.Args[2],"和除数os.Args[3]=",os.Args[3]) //os.Exit(1) } service:=os.Args[1] client,err:=jsonrpc.Dial("tcp",service) if err != nil { log.Fatal("Dial 发生了错误了哦 错误的信息为 err=",err) } send:=Send{os.Args[2],os.Args[3]} var resive string err1:=client.Call("DemoM.DoWork",send,&resive) if err1!=nil { fmt.Println("shiming call error ") fmt.Println("Call 的时候发生了错误了哦 err=",err1) } fmt.Println("收到信息了",resive)}// 类可以不一样 但是 Who 和DoWhat 要必须一样 要不然接收到不到值,等我在详细的了解了 才去分析下原因 感觉有点蒙蔽啊type Send struct { Who, DoWhat string}
E:\new_code\GoDemo\web_server>go run GoJSONRPCWeb11.go 127.0.0.1:8080 shiming gongzuo这是客户端,用来启动,通过命令行来启动客户端 其他端 去调用的地方 对应的例子是 GoTCPRPC9.go长度必须等于4,因为呢,你输入的肯定是一个ip的地址ip= 127.0.0.1:8080 嘿嘿,加上后面的被除数os.Args[2]= shiming 和除数os.Args[3]= gongzuo收到信息了 是谁:shiming,在做什么---gongzuoE:\new_code\GoDemo\web_server>go run GoJSONRPCWeb11.go 127.0.0.1:8080 shiming qiaodaima这是客户端,用来启动,通过命令行来启动客户端 其他端 去调用的地方 对应的例子是 GoTCPRPC9.go长度必须等于4,因为呢,你输入的肯定是一个ip的地址ip= 127.0.0.1:8080 嘿嘿,加上后面的被除数os.Args[2]= shiming 和除数os.Args[3]= qiaodaima收到信息了 是谁:shiming,在做什么---qiaodaima
os.Args
is an array var Args []string
, obtained through input, and then the content of the client input to the server, the server to do some operations, and then return to the client
Go
has provided a RPC
good support, through HTTP
TCP
JSONRPC
the implementation, can be very convenient to develop distributed Web
applications, but I do not, in the study. Unfortunately there is Go
no SOAP RPC
support provided ~ ~ ~