[Go] 왕초보 grpc 튜토리얼 - 간단한 서버-클라이언트 메시지 교환

2022. 3. 28. 11:18·IT/개발 언어 및 도구

이 포스팅은 아래의 유튜브 영상 튜토리얼 내용을 정리한 것입니다. 문제 시 댓글 주십시오. 삭제하겠습니다.

이전의 제 protocol buffer 왕초보 튜토리얼을 먼저 보고 오시면 본 포스팅을 이해하는 데 더욱 도움이 될 것입니다.

본 포스팅과 동시에 저 영상을 시청할 것을 권합니다. 과정을 한 단계 한 단계 따라가시면 더욱 공부하기 좋습니다. 완성된 코드를 보는 것보다 코드의 과정을 처음부터 하나씩 따라가며 익히는게 왕초보공부의 핵심입니다.

 

gRPC란?

gRPC란 원격 procedure call을 지원해주는 프레임워크이다. 어디서든 실행될 수 있다.

원격 procedure call은 분산 시스템에서 주로 쓰이는 것으로, application 간의 통신을 가능하게 해준다.

 

 

참고로 grpc 쓰려면 golang이 1.17 버전 이상이여야하는 것 같다. 그래서 다시 까느라 애 무지 먹었다 ㅠㅠ. 다음 링크를 참고해서 1.17 버전의 go를 설치해주자. 이떄 기존의 go를 삭제하고 깔아주는 것 명심하자. (더보기 클릭)

더보기

https://tecadmin.net/install-go-on-ubuntu/

 

How To Install Go 1.17 on Ubuntu 18.04 & 16.04 LTS

Installing go on Ubuntu. Go has released latest version 1.17. install Go 1.17 on your Ubuntu 19.10, 18.04, 16.04 LTS systems.

tecadmin.net

 

https://www.youtube.com/watch?v=BdzYdN_Zd9Q 

위의 튜토리얼을 따라하며 gRPC를 이용한 간단한 채팅 서비스를 만들어본다.

들어가기에 앞서 명령어를 통해 grpc 패키지를 설치한다.

go get -u google.golang.org/grpc

제일 처음으로 server.go라는 파일을 만들어준다.

  • net 패키지를 사용하여, tcp 포트 9000번에서 client의 신호를 기다린다. lis는 listener라는 뜻이다.
  • grpc를 패키지를 사용하여, 그grpcServer를 생성한 뒤에, 그곳에 listener을 등록해준다.
  • → TCP 연결에 전달하기 전에, grpc 서버에 endpoint들을 등록할 수 있게 해준다.

참고로, NewServer()은 chat.pb.go에 자동으로 만들어진 함수이다.

// server.go
package main

import (
	"log" 
	"net"
	"google.golang.org/grpc"
)

func main()
{
	lis, err := net.Listen("tcp", ":9000") // tcp 연결을 만든다. (포트 9000번에서)
	if err != nil {
		log.Fatalf("Failed to listend on port 9000: %v", err)
	}
	
	grpcServer := grpc.NewServer()

	if err := grpcServer.Serve(lis); err != nil {
		log.Fatalf("Failed to serve gRPC server over port 9000: %v", err)
	}
}

이렇게 서버를 만들어주면, 아무 일 안하는 서버가 하나 만들어진다.

이제는 다음과 같이 chat.proto 파일을 만들어준다.

client로 부터 메시지를 받고, 바로 서버 측 메시지를 돌려주는 프로그램을 만들 예정이다.

  • 보내줄 메시지의 형식으로 string 타입의 body를 선언해준다.
    • proto에 저장되는 데이터 구조체는 message 타입으로 정의된다.
  • 서비스 또한 정의해주었다.
    • service 타입의 chatService를 선언해준다.
    • rpc 타입의 함수를 정의했다.
    • → 어떤 언어로 쓰인 grpc 클라이언트던 간에 모두 호출할 수 있는 함수가 된다.
    • SayHello()는 인자로 메시지를 받고, 리턴으로 메시지를 돌려주는 함수이다.
// chat.proto
syntax = "proto3";
package chat;

message Message {
	string body = 1;
}

service ChatService {
	rpc SayHello(Message) returns (Message) {}
}

그 다음으로 chat 폴더 안에 chat 패키지를 만들 것이다.

터미널에다 대고 다음 명령어를 입력해, proto 파일을 컴파일해준다. 이러면 chat 디렉토리 안에 chat.pb.go 파일이 생성된다.

mkdir chat
protoc --go_out=plugins=grpc:chat chat.proto

chat.pb.go에는 chat service와 대화하거나 grpc에 서버나 클라이언트를 등록하는 데 필요한 것들이 갖춰져 있게된다.

이제 chat 패키지의 일부가 될 chat.go 파일을 만들어주자.

  • 비어있는 Server 구조체를 만들고, SayHello rpc 함수를 만들어준다. 리턴값으로는 메시지 포인터 혹은 에러를 리턴할 것이다.→ 따라서 아무것도 추가로 import 할 필요가 없다.
  • → 이때, chat.pb.go 안에 SayHello의 프로토타입이 아래와 같이 만들어져있다.
  • SayHello에서는 서버에 client가 받은 메시지를 띄워준 다음, 클라이언트로 서버의 메시지를 보내주게 된다.
  • 참고) context란?→ 한마디로 context는 하나의 “맥락”이고, 이 “맥락”을 프로세스나 API에 전달해서 모든 연계되는 작업들이 하나의 맥락 안에서 이뤄지도록 하는 것이다. (참고 : https://devjin-blog.com/golang-context/ )
    → 하나의 “맥락”을 유지하기 위해, 다른 함수를 호출할 때 예제와 같이 context를 첫번째 인자로 전달한다고 한다.
// chat.go
package chat

import (
	"log" // 들어오는 모든 request들을 log에 저장한다.
	"golang.org/x/net/context" // context를 request로 받을 수 있게 한다.
)

type Server struct { // 비어있는 서버 구조체 생성
}

func (s *Server) SayHello(ctx context.Context, message *Message) (*Message, error)
{
	log.Printf("Recieved message body from client: %s", message.Body)
	return &Message{Body: "Hello From the Server!"}, nil // 실패 시 error로 nil 리턴
}

 

먼저 다음 명령어를 실행해서 모듈(go.mod)을 만들어주자. 모듈이라는 건 로컬에서 만든 패키지를 import 하는 데 필요한 것 같다.

go mod init github.com/Seo-A-Nam/Etc/go_grpc_practice

이제 server.go를 수정해준다.

chat.RegisterChatServiceSever()을 통해 말그대로 chat 서비스 서버를 등록해준다.

→ 인자로 grpc 서버와 서버 구조체를 넣어준다.

// server.go 수정
package main

import (
	"log" 
	"net"
	"google.golang.org/grpc"
	"github.com/Seo-A-Nam/Etc/go_grpc_practice/chat"
)

func main()
{
	lis, err := net.Listen("tcp", ":9000") // tcp 연결을 만든다. (포트 9000번에서)
	if err != nil {
		log.Fatalf("Failed to listend on port 9000: %v", err)
	}
	
	s := chat.Server{} // 서버 구조체를 선언
	grpcServer := grpc.NewServer() // grpc 서버를 생성한다.

	chat.RegisterChatServiceServer(grpcServer, &s) // chat service에 서버 등록
	if err := grpcServer.Serve(lis); err != nil {
		log.Fatalf("Failed to serve gRPC server over port 9000: %v", err)
	}
}

이제 server.go를 실행해주자.

그럼 이렇게 계속 메시지를 대기하고 있는 상태가 된다.

로컬 호스트의 9000번 포트에서 listening을 시작한 것이다.

이제 client.go라는 클라이언트 파일을 만들어주자

참고로, grpc.WithInsecure()라는 옵션은 insecure connection을 생성한다는 것으로, 둘 사이 통신에서 별다른 보안을 챙기지 않겠다는 뜻이다. 보안이 중요하고 서버 간 통신이 외부에 노출될 수 있는 상황이면, 이 옵션을 제거해서 connection을 맺을 때 credential을 확인하는 절차가 필요하다고 한다.

// client.go
package main

import (
	"log"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"github.com/Seo-A-Nam/Etc/go_grpc_practice/chat"
)

func main() {
	var conn *grpc.ClientConn // grpc 클라이언트의 connection을 저장하는 포인터
	conn, err := grpc.Dial(":9000", grpc.WithInsecure())
	// 로컬 호스트의 9000번 포트에 있는 grpc 서버와 연결을 시도한다. (connection을 생성해준다)
	if err != nill {
		log.Fatalf("could not connect: %s", err)
	}
	
	defer conn.Close() // defer : 함수가 끝나려고 할 때 이 코드를 실행한다.
	
	c := chat.NewChatServiceClient(conn) // 연결포인터를 인자로 전달
	
	message := chat.Message { // 클라이언트 메시지
		Body: "Hello from the client!",
	}

	response, err := c.SayHello(context.Background(), &message)
	if err != nill {
		log.Fatalf("Error when calling SayHello: %s", err)
	}
	log.Printf("Response from Server: %s", response.Body)
}

이제 client.go도 실행해보고 결과가 어떻게 되는 지 보자.

이런 결과가 나타나게 되는 것을 볼 수 있다.

원래 처음 해보면 하나도 안 이해 되는게 정상이지만, 점점 하다보면 익숙해지면서 간단하게 느껴질 것이라고 한다.

그러니 나도 계속 복습해야겠다...

저작자표시 (새창열림)

'IT > 개발 언어 및 도구' 카테고리의 다른 글

[연구] 컨테이너넷 (containernet) 프레임워크 소개  (0) 2022.07.13
[Go] 고 루틴(go routine)의 활용 - 기초  (0) 2022.05.27
[Go] protocol buffer 왕초보 실습  (0) 2022.03.28
'IT/개발 언어 및 도구' 카테고리의 다른 글
  • [연구] 컨테이너넷 (containernet) 프레임워크 소개
  • [Go] 고 루틴(go routine)의 활용 - 기초
  • [Go] protocol buffer 왕초보 실습
남서아 (구 - 밥한그릇배따시게)
남서아 (구 - 밥한그릇배따시게)
학습하고 정리한 내용 중, 공유할만한 것들을 포스팅합니다. / 소프트웨어 학사 (2025년도 2월 졸업)
  • 남서아 (구 - 밥한그릇배따시게)
    Wendy 기술블로그
    남서아 (구 - 밥한그릇배따시게)
  • 전체
    오늘
    어제
  • 공지사항

    • 개발자 정보 및 포트폴리오
    • 포스팅 목적
  • 링크

    • Portfolio
    • 분류 전체보기 (99)
      • IT (59)
        • 클라우드 & 인프라 (2)
        • CS 공부 (12)
        • 42Seoul (19)
        • 개발 언어 및 도구 (4)
        • 개발 환경 및 설치 (5)
        • 튜토리얼 및 가이드 (10)
        • Data & AI (5)
        • ETC (2)
      • Experience (4)
      • English (32)
        • 회화 (5)
        • 자격증 공부 (26)
        • 후기 (1)
      • 근황 (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
남서아 (구 - 밥한그릇배따시게)
[Go] 왕초보 grpc 튜토리얼 - 간단한 서버-클라이언트 메시지 교환
상단으로

티스토리툴바