go 원생 rpc 패키지 사용: 데 이 터 를 전달 하 는 캐리어: golang 패키지 http 프로 토 콜 / tcp / jsonrpc
13904 단어 MQ/미들웨어/RPC
rpc 는 2 가지 내용 에 주목 합 니 다. 1. 전송 방식 - 서버 의 캐리어 - 데 이 터 를 전달 하 는 프로 토 콜 - rpc 는 세 션 계층 의 의사 소통 방식 이기 때문에 전송 하 는 하층 의 어느 층 에 연결 하 는 지 고려 해 야 합 니 다. 프로 토 콜 - http 프로 토 콜 을 바탕 으로 하 는 지, tcp 연결 에 연결 되 어 있 는 지, 2. 서버 와 클 라 이언 트 가 공동으로 사용 하 는 - 데이터 전송 형식: json / xml / protobuf 데이터 전송 형식 과 캐리어 를 통일 하면 클 라 이언 트 로 서버 의 rpc 서 비 스 를 호출 할 수 있 고 클 라 이언 트 는 언어 를 제한 하지 않 습 니 다.
JSON 과 protobuf 는 다 중 언어 를 지원 합 니 다. - 즉, 이 프로 토 콜 들 은 자바 와 같은 다른 언어 로 번역 할 수 있 습 니 다.golang 공식
net/rpc
라 이브 러 리 사용 encoding/gob
을 디 코딩 하여 http 와 tcp 프로 토 콜 의 전송 방식 을 지원 합 니 다.RPC 가 뭐야?
원 격 프로 세 스 호출 (Remote Procedure Call, RPC 로 약칭) 은 컴퓨터 통신 프로 토 콜 입 니 다.이 프로 토 콜 은 한 컴퓨터 에서 실행 되 는 프로그램 에서 다른 컴퓨터 의 서브루틴 을 호출 할 수 있 으 며, 프로그래머 는 이 상호작용 을 위해 프로그램 을 작성 할 필요 가 없다.관련 소프트웨어 가 대상 을 대상 으로 프로 그래 밍 을 한다 면 원 격 프로 세 스 호출 도 원 격 호출 또는 원 격 방법 호출 이 라 고 할 수 있다.위 키 백과: 원 격 프로 세 스 호출
통속 적 이 고 알 기 쉬 운 언어 로 설명 하면 RPC 는 기 계 를 뛰 어 넘 고 언어 를 뛰 어 넘 는 컴퓨터 프로그램 을 사용 하 는 방법 을 허용 하 는 것 이다.예 를 들 어 저 는 go 언어 로 사용자 정 보 를 얻 는 방법 getUser Info 를 썼 고 go 프로그램 을 아 리 클 라 우 드 서버 에 배 치 했 습 니 다. 지금 저 는 텐 센트 클 라 우 드 에 배 치 된 phop 프로젝트 가 있 습 니 다. golang 의 getUser Info 방법 으로 사용자 정 보 를 얻 어야 합 니 다. phop 크로스 기기 가 go 방법 을 호출 하 는 과정 은 바로 RPC 호출 입 니 다.
golang 에서 RPC 를 어떻게 실현 합 니까?
골 랑 에서 RPC 를 실현 하 는 것 은 매우 간단 하 며, 포 장 된 공식 라 이브 러 리 와 일부 제3자 라 이브 러 리 가 지원 합 니 다.Go RPC 는 tcp 나 http 를 이용 해 데 이 터 를 전달 할 수 있 으 며, 전달 할 데이터 에 대해 서 는 다양한 종류의 코딩 방식 을 사용 할 수 있다.golang 공식
net/rpc
라 이브 러 리 사용 encoding/gob
을 디 코딩 하여 지원 tcp
또는 http
데이터 전송 방식 을 지원 합 니 다. 다른 언어 는 지원 되 지 않 기 때문에 gob
라 이브 러 리 에서 실 현 된 RPC 방법 을 사용 하여 언어 간 디 코딩 을 할 수 없습니다.골 랑 은 공식 적 으로
net/rpc
라 이브 러 리 를 제공 하여 RPC 를 실현 하 는 방법 도 제 공 했 고 JSON RPC 는 JSON 으로 데이터 디 코딩 을 하기 때문에 크로스 언어 호출 을 지원 합 니 다.그러나 현재 jsonrpc 라 이브 러 리 는 tcp 프로 토 콜 을 기반 으로 이 루어 졌 으 며 http 로 데이터 전송 을 하 는 것 은 잠시 지원 되 지 않 습 니 다.골 랑 이 공식 적 으로 제공 하 는 rpc 라 이브 러 리 를 제외 하고 많은 제3자 라 이브 러 리 가 골 랑 에서 RPC 를 실현 하 는 데 지원 을 제공 합 니 다. 대부분의 제3자 rpc 라 이브 러 리 의 실현 은
net/rpc/jsonrpc
데이터 디 코딩 을 사용 합 니 다. protobuf
성명 파일 에 따라 rpc 방법 정의 와 서비스 등록 코드 를 자동 으로 생 성하 여 골 랑 에서 rpc 서비스 호출 을 편리 하 게 할 수 있 습 니 다.rpc
rpc 패 키 지 는 네트워크 나 다른 I / O 를 통 해 대상 에 연결 하 는 외부 방법 을 제공 합 니 다.
jsonrpc
jsonrpc 패 키 지 는 rpc 패 키 지 를 사용 하여 JSON - RPC 의 클 라 이언 트 디코더 와 서버 의 디코더 를 실현 합 니 다.
다음은 golang 공식
protobuf
라 이브 러 리 를 사용 하여 RPC 를 실현 하 는 방법 을 보 여 줍 니 다. net/rpc
을 RPC 의 캐리어 로 사용 하고 http
패키지 로 클 라 이언 트 연결 요청 을 감청 합 니 다.정확히 말 하면, 나 는 golang 봉 인 된 http 프로 토 콜 을 사용 하여 통신 을 하 는 연결 이 라 고 생각 하 는데, 모두 rpc 의 server 엔 드 stub 에 등록 되 었 다.//
package main
import (
"errors"
"fmt"
"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
}
//test http rpc
func main() {
arith := new(Arith)
rpc.Register(arith)// rpc server-called
rpc.HandleHTTP()// http rpc server-stub
go func() {
err := http.ListenAndServe(":1234", nil)
if err != nil {
fmt.Println(err.Error())
}
}()
go func() {
err1 := http.ListenAndServe(":12341", nil)
if err1 != nil {
fmt.Println(err1.Error())
}
}()
select{}
}
============================== ===================
package main
import (
"fmt"
"log"
"net/rpc"
)
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
func main() {
serverAddress := "127.0.0.1"
client, err := rpc.DialHTTP("tcp", serverAddress+":1234") //!!!!!!!! client-stub
if err != nil {
log.Fatal("dialing:", err)
}
// Synchronous call
args := Args{17, 8}
var reply int
err = client.Call("Arith.Multiply", args, &reply)//!!!!!!!!client-call
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d
", args.A, args.B, reply)
var quot Quotient
err = client.Call("Arith.Divide", args, ")
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d/%d=%d remainder %d
", args.A, args.B, quot.Quo, quot.Rem)
test(serverAddress)
}
func test(serverAddress string){
fmt.Println("===question2--from-port-12341")
client, err := rpc.DialHTTP("tcp", serverAddress+":12341")
if err != nil {
log.Fatal("dialing:", err)
}
// Synchronous call
args := Args{17, 8}
var reply int
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d
", args.A, args.B, reply)
var quot Quotient
err = client.Call("Arith.Divide", args, ")
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d/%d=%d remainder %d
", args.A, args.B, quot.Quo, quot.Rem)
}
net / rpc / jsonrpc 라 이브 러 리
위의 예 에서 우 리 는
net/http
을 사용 하여 RPC 를 실현 하 는 과정 을 보 여 주 었 으 나 다른 언어 에서 위의 예 에서 실 현 된 RPC 방법 을 호출 할 수 없 었 다.그래서 다음 예 는 net/rpc
라 이브 러 리 를 사용 하여 RPC 를 실현 하 는 방법 을 보 여 줍 니 다. 이 방식 으로 실 현 된 RPC 방법 은 크로스 언어 호출 을 지원 합 니 다.$GOPATH/src/test/rpc/jsonrpc_server.go
package main
import (
"errors"
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
//
type Arith struct {
}
//
type ArithRequest struct {
A int
B int
}
//
type ArithResponse struct {
Pro int //
Quo int //
Rem int //
}
//
func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
res.Pro = req.A * req.B
return nil
}
//
func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error {
if req.B == 0 {
return errors.New("divide by zero")
}
res.Quo = req.A / req.B
res.Rem = req.A % req.B
return nil
}
func main() {
rpc.Register(new(Arith)) // rpc
lis, err := net.Listen("tcp", "127.0.0.1:8096")
if err != nil {
log.Fatalln("fatal error: ", err)
}
fmt.Fprintf(os.Stdout, "%s", "start connection")
for {
conn, err := lis.Accept() //
if err != nil {
continue
}
go func(conn net.Conn) { //
fmt.Fprintf(os.Stdout, "%s", "new client in coming
")
jsonrpc.ServeConn(conn)
}(conn)
}
}
상기 서버 프로그램 이 시작 되면 로 컬 8096 포트 를 감청 하고 클 라 이언 트 의 tcp 연결 요청 을 처리 합 니 다.우 리 는 golang 으로 클 라 이언 트 프로그램 이 상기 서버 에 연결 되 고 RPC 호출 을 할 수 있 습 니 다.
$GOPATH/src/test/rpc/jsonrpc_client.go
package main
import (
"fmt"
"log"
"net/rpc/jsonrpc"
)
//
type ArithRequest struct {
A int
B int
}
//
type ArithResponse struct {
Pro int //
Quo int //
Rem int //
}
func main() {
conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8096")
if err != nil {
log.Fatalln("dailing error: ", err)
}
req := ArithRequest{9, 2}
var res ArithResponse
err = conn.Call("Arith.Multiply", req, &res) //
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d * %d = %d
", req.A, req.B, res.Pro)
err = conn.Call("Arith.Divide", req, &res)
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d / %d, quo is %d, rem is %d
", req.A, req.B, res.Quo, res.Rem)
}
protorpc 라 이브 러 리
크로스 언어 호출 을 실현 하기 위해 golang 에서 RPC 방법 을 실현 할 때 우 리 는 크로스 언어의 데이터 코딩 방식 을 선택해 야 한다. 예 를 들 어 JSON, 상기
net/rpc/jsonrpc
는 이 요 구 를 만족 시 킬 수 있 지만 http 전송 을 지원 하지 않 고 데이터 코딩 성능 이 높 지 않다 는 단점 도 있다.그래서 일부 제3자 rpc 라 이브 러 리 는 jsonrpc
데이터 디 코딩 을 선택 하고 서비스 등록 코드 자동 생 성 기능 을 제공 합 니 다.아래 의 예 는 RPC 방법 과 요청 응답 파 라 메 터 를 정의 하고 제3자 protobuf
라 이브 러 리 를 사용 하여 RPC 서비스 등록 코드 를 생 성 합 니 다.우선, 설치
protobuf
및 protorpc
명령 을 실행 할 수 있 습 니 다.그리고 실행 할 RPC 방법 과 관련 된 인 자 를 정의 하 는 proto 파일 을 만 듭 니 다.
$GOPATH/src/test/rpc/pb/arith.proto
syntax = "proto3";
package pb;
//
message ArithRequest {
int32 a = 1;
int32 b = 2;
}
//
message ArithResponse {
int32 pro = 1; //
int32 quo = 2; //
int32 rem = 3; //
}
// rpc
service ArithService {
rpc multiply (ArithRequest) returns (ArithResponse); //
rpc divide (ArithRequest) returns (ArithResponse); //
}
다음은 위 에서 정의 한
protobuf
파일 에 따라 RPC 서비스 코드 를 생 성 해 야 합 니 다.먼저 protoc
라 이브 러 리 를 설치 한 다음 arith.proto
도 구 를 사용 하여 코드 를 생 성 합 니 다. protorpc
명령 을 실행 한 후 go get github.com/chai2010/protorpc
파일 과 같은 등급 의 디 렉 터 리 에 protoc
파일 을 생 성 했 습 니 다. 그 안에 RPC 방법 정의 와 서비스 등록 코드 가 포함 되 어 있 습 니 다.생 성 된
protoc --go_out=plugin=protorpc=. arith.proto
코드 를 기반 으로 rpc 서버 를 실현 합 니 다.$GOPATH/src/test/rpc/protorpc_server.go
package main
import (
"errors"
"test/rpc/pb"
)
//
type Arith struct {
}
//
func (this *Arith) Multiply(req *pb.ArithRequest, res *pb.ArithResponse) error {
res.Pro = req.GetA() * req.GetB()
return nil
}
//
func (this *Arith) Divide(req *pb.ArithRequest, res *pb.ArithResponse) error {
if req.GetB() == 0 {
return errors.New("divide by zero")
}
res.Quo = req.GetA() / req.GetB()
res.Rem = req.GetA() % req.GetB()
return nil
}
func main() {
pb.ListenAndServeArithService("tcp", "127.0.0.1:8097", new(Arith))
}
이 프로그램 을 실행 하면 로 컬 8097 포트 를 감청 하고 클 라 이언 트 의 tcp 연결 을 받 습 니 다.
protoc
을 바탕 으로 클 라 이언 트 프로그램 을 다시 실현 합 니 다.$GOPATH/src/test/protorpc_client.go
package main
import (
"fmt"
"log"
"test/rpc/pb"
)
func main() {
conn, err := pb.DialArithService("tcp", "127.0.0.1:8097")
if err != nil {
log.Fatalln("dailing error: ", err)
}
defer conn.Close()
req := &pb.ArithRequest{9, 2}
res, err := conn.Multiply(req)
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d * %d = %d
", req.GetA(), req.GetB(), res.GetPro())
res, err = conn.Divide(req)
if err != nil {
log.Fatalln("arith error ", err)
}
fmt.Printf("%d / %d, quo is %d, rem is %d
", req.A, req.B, res.Quo, res.Rem)
}
어떻게 언어 간 에 golang 의 RPC 방법 을 호출 합 니까?
위의 세 가지 예 를 들 어 우 리 는 각각
arith.proto
, arith.pb.go
, arith.pb.go
을 사용 하여 golang 중의 RPC 서버 를 실현 하고 해당 하 는 golang 클 라 이언 트 RPC 호출 예 시 를 제시 했다. JSON 과 protobuf 는 다 중 언어 를 지원 하기 때문에 ariti.pb.go
와 net/rpc
실 현 된 RPC 방법 을 사용 하면 우 리 는 다른 언어 에서 호출 할 수 있다.다음은 php 클 라 이언 트 프로그램 을 제공 합 니 다. socket 연결 을 통 해 jsonrpc 를 호출 하 는 서버 RPC 방법 입 니 다.$PHPROOT/jsonrpc.php
conn = fsockopen($host, $port, $errno, $errstr, 3);
if (!$this->conn) {
return false;
}
}
public function Call($method, $params) {
if (!$this->conn) {
return false;
}
$err = fwrite($this->conn, json_encode(array(
'method' => $method,
'params' => array($params),
'id' => 0,
))."
");
if ($err === false) {
return false;
}
stream_set_timeout($this->conn, 0, 3000);
$line = fgets($this->conn);
if ($line === false) {
return NULL;
}
return json_decode($line,true);
}
}
$client = new JsonRPC("127.0.0.1", 8096);
$args = array('A'=>9, 'B'=>2);
$r = $client->Call("Arith.Multiply", $args);
printf("%d * %d = %d
", $args['A'], $args['B'], $r['result']['Pro']);
$r = $client->Call("Arith.Divide", array('A'=>9, 'B'=>2));
printf("%d / %d, Quo is %d, Rem is %d
", $args['A'], $args['B'], $r['result']['Quo'], $r['result']['Rem']);
기타 RPC 라 이브 러 리
위 에서 언급 한 세 가지 golang 에서 RPC 를 실현 하 는 방식 을 제외 하고 다른 rpc 라 이브 러 리 는 비슷 한 기능 을 제공 합 니 다. 비교적 유명한 구 글 오픈 소스 가 있 는 grpc 이지 만 grpc 의 첫 설치 가 비교적 번 거 롭 습 니 다. 여 기 는 더 이상 소개 하지 않 고 관심 이 있 는 것 은 스스로 알 수 있 습 니 다.
참고 자료