Golangrpc 패키지 사용 안내
6254 단어 RPC
rpc 패키지는 네트워크나 기타I/0를 통해 연결된 대상에 대한 내보내기 방법에 대한 접근을 제공합니다.서버는 개체를 개체 유형 이름을 가진 가시적인 서비스로 등록합니다.등록 후 객체의 내보내기 방법에 원격으로 액세스할 수 있습니다.서버는 서로 다른 유형의 여러 대상 서비스를 등록할 수 있지만 같은 유형의 여러 대상을 등록하는 것은 잘못된 것이다.그리고 대상의 방법은 아래의 조건을 충족시켜야만 원격 호출을 사용할 수 있으며, 그렇지 않으면 방법은 무시될 수 있다.func (t *T) MethodName(argType T1, replyType *T2) error
T1와 T2는 encoding/gob를 통해 인코딩할 수 있다.방법의 첫 번째 파라미터는 호출자가 제공한 파라미터를 대표하고, 두 번째 파라미터는 호출자에게 되돌아오는 결과 파라미터를 대표한다.방법이 되돌아오는 값이 비어 있지 않으면 되돌아오는 reply 파라미터는 클라이언트에게 되돌아오지 않습니다.예제
서버 프로세싱 프로세스
Register 또는 RegisterName를 사용하여 rpc 서비스를 등록한다.Listen 방법으로 로컬 네트워크의 주소를 직접 감청하고 정부에서 준 예에서 감청하기 전에 rpc.HandleHTTP 방법을 사용했다.// rpc.HandleHTTP()
func HandleHTTP() {
DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
}
const (
DefaultRPCPath = "/_goRPC_"
DefaultDebug = "/debug/rpc"
)
func (server *Server) HandleHTTP(rpcPath, debugPath string) {
http.Handle(rpcPath, server)
http.Handle(debugPath, debugHTTP{server})
}
두 개
handler를 등록하여 서비스 호출 상황을 볼 수 있습니다.예를 들어 Listen 감청localhost:1234 네트워크를 사용하면 루트localhost:1234/debug/rpc를 통해 다음과 같은 내용을 볼 수 있다.http.Serve 방법을 사용하여 다가올 HTTP 연결을 수신하고 각 연결에 새로운 서비스를 만들 것이다goroutine.모든 서비스는 요청을 읽고 handler 호출해서 그들에게 회답할 것입니다.handler는 보통nil이며, 이때DefaultServeMux는 사용된다.func Serve(l net.Listener, handler Handler) error {
srv := &Server{Handler: handler}
return srv.Serve(l)
}
func (srv *Server) Serve(l net.Listener) error {
// ...
for {
rw, e := l.Accept()
if e != nil {
// ...
}
c := srv.newConn(rw)
c.setState(c.rwc, StateNew)
go c.serve(ctx)
}
}
위의
http.Serve 방법도 다른 방법으로 처리할 수 있다. 예를 들어 Accept 인터페이스와 ServeConn 방법, 그리고 for 문장을 사용하여 지속적인 처리 요청을 실현할 수 있다.두 번째 단계에서 Listen 방법은 listener 감청 대상을 되돌려주고 그 위에 Accept 방법을 호출한다.호출이 성공하면 사용 가능한 연결이 되돌아옵니다.그리고 rpc.ServeConn 방법을 사용해서 이 연결에서 기본 서비스를 실행합니다.ServeConn 클라이언트가 중단될 때까지 차단됩니다.보통 go를 사용하여 병발ServeConn하고, ServeConn 방법은 gob 형식의 codec를 사용하며, 교체가 필요하면 ServeCodec 방법을 사용합니다.rpc가방은 두 가지codec를 제공한다. 하나는 gob, 하나는 json이다.// ...
listener, err := net.Listen("tcp", ":1234")
if err != nil {
fmt.Println("failed to listen tcp, error:", err)
}
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("failed to accept connection, error:", err)
}
go rpc.ServeConn(conn)
}
서버 전체 예
package main
import (
"errors"
"fmt"
"net"
"net/http"
"net/rpc"
)
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
type Arith int
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
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.B
return nil
}
func main() {
arith := new(Arith)
err := rpc.Register(arith)
if err != nil {
fmt.Println("failed to register rpc service. error: ", err)
return
}
rpc.HandleHTTP()
l, err := net.Listen("tcp", ":1234")
if err != nil {
fmt.Println("listen error:", err)
}
if err = http.Serve(l, nil); err != nil {
fmt.Println("failed to accept incoming request. error: ", err)
return
}
}
클라이언트 프로세스
Dial 서비스를 연결합니다.연결이 완료되면 새 클라이언트가 생성됩니다.RPC 방법도 사용할 수 있다. DialHTTP는 특정 네트워크 주소의 DialHTTP 서비스에 연결하고 기본값HTTP RPC 경로를 감청한다.func DialHTTP(network, address string) (*Client, error) {
return DialHTTPPath(network, address, DefaultRPCPath)
}
func DialHTTPPath(network, address, path string) (*Client, error) {
var err error
conn, err := net.Dial(network, address)
if err != nil {
return nil, err
}
// ...
}
HTTP RPC 인터페이스를 호출하고 Call 인터페이스는 지정한 Call 서비스를 호출하여 완료를 기다린 후 오류 상태를 되돌려줍니다.RPC 인터페이스는 동기화 호출Call 서비스로 비동기화 호출이 필요하면 클라이언트에서 호출RPC 인터페이스를 사용할 수 있습니다.func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
// ...
}
호출이 잘못되지 않았다면, 위에서 되돌아온
Go 중 Call 채널은 오류가 없는 Done 로 전송될 것입니다.잘못 여부에 따라 호출 성공 여부를 판단할 수 있다.예를 들면 다음과 같습니다.// ...
quotient := new(Quotient)
divCall := client.Go("Arith.Divide", args, quotient, nil)
replyCall := 클라이언트 전체 예
package main
import (
"fmt"
"net/rpc"
)
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
func main() {
client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
if err != nil {
fmt.Println("failed to dial http rpc server, error:", err)
}
// Synchronous call
args := &Args{7, 8}
var reply int
if err = client.Call("Arith.Multiply", args, &reply); err != nil {
fmt.Println("failed to call function synchronously, error:", err)
}
fmt.Printf("Arith: %d*%d=%d
", args.A, args.B, reply)
// Asynchronous call
quotient := new(Quotient)
divCall := client.Go("Arith.Divide", args, quotient, nil)
replyCall :=