gRPC로 python과 go 연결하기

진영민·2023년 1월 16일
0

잡다한 상식

목록 보기
12/22

gRPC

구글에서 개발한 RPC 플랫폼
protocol buffer와 RPC를 사용한다.

SSL/TLS를 사용하여 암호화하며, HTTP2.0을 사용한다.

서버의 함수를 클라이언트에서 호출할 수 있어 MSA를 쉽게 구현할 수 있다.

대부분의 언어를 지원하여 언어가 다른 서버간의 통신을 쉽게 구현할 수 있다.

Golang grpc client

먼저, 서버와 클라이언트에서 동일한 proto를 정의해야 한다.

이번 예시로는 서버간의 연결을 확인해 주는 Connect함수를 정의했다.

sound.proto
syntax = "proto3";

package sound;

option go_package="sound/sound";

service File{
    rpc Connect (Ping) returns (Pong);
}

message Ping{
    string ping=1;
}

message Pong{
    string pong=1;
}

이제 터미널을 이용하여 proto 관련 프로그램을 설치해 주도록 하자.

go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28

go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2

protoc --go_out=. --go-grpc_out=. ./sound/sound.proto

공식 docs에서는

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./sound/sound.proto

의 명령어를 사용하라고 했지만, --go_opt와 --go-grpc_opt 를 인식하지 못하여 빼고 한 결과 정상적으로 파일이 생성되었다.

여기까지 잘 따라오면 sound_grpc.pb.gosound.pb.go가 생성되었을 것이다.

이제

package grpc

import (
	"context"
	"log"
	pb "solution/grpc/sound/sound"
	"time"

	"google.golang.org/grpc"
)

func Ping() {
	//연결되는 서버 정의
    conn, err := grpc.Dial("localhost:8080", grpc.WithInsecure(), grpc.WithBlock())
    
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
    //client 생성
	c := pb.NewFileClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	//Ping 전송
	r, err := c.Connect(ctx, &pb.Ping{Ping: "Ping!"})
	if err != nil {
		log.Fatalf("could not request: %v", err)
	}

	log.Printf("Config: %v", r)
}

이제 Ping()의 함수를 실행시키면 localhost:8080의 서버에 grpc연결 요청을 보내고, Connect 함수를 실행시킬 수 있다.

python gRPC server

파이썬에서도 proto를 정의해야 한다.
하지만 go에서 한 것과 크게 다르지 않다.

//sound.proto
syntax = "proto3";

package sound;

service File{
    rpc Connect (Ping) returns (Pong);
}

message Ping{
    string ping=1;
}

message Pong{
    string pong=1;
}

이제

python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. ./sound.proto

의 명령어를 터미널에서 동작하면 go의 경우와 마찬가지로 두개의 파일이 생성될 것이다.
sound_pb2_grpc.py
sound_pb2.py
이제 서버에서 이 두 파일을 import하여 사용할 수 있다.

//server.py
from concurrent import futures
import logging

import grpc
#생성된 파일 import
import sound_pb2
import sound_pb2_grpc

#File 클래스 정의, 인자는 Servicer을 붙어야 한다.
class File(sound_pb2_grpc.FileServicer):

	#request로 받아 결과를 return해야 한다.
    def Connect(self, request, context):
        print(request.ping)
        return sound_pb2.Pong(pong='%s Pong!' % request.ping)


def serve():
	#멀티스레딩 설정
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    
    sound_pb2_grpc.add_FileServicer_to_server(File(), server)
    
    #8080번 포트로 서버 열기
    server.add_insecure_port('[::]:8080')
    print("server on port 8080")
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    logging.basicConfig()
    serve()

이러한 방법으로 python server를 만들 수 있으며, python 서버를 연 상태로 go의 코드를 실행시키면 서로 통신하여 Connect 함수를 실행시킬 수 있다.

profile
코린이

0개의 댓글