1일차에 만든 game.pb.go를 토대로 핑 보내보기

package main
 
import (
    "fmt"
    "game-server/protocol"
    "time"
    "server/protocol"
    "google.golang.org/protobuf/proto"
)
 
  
func main() {
 
    // 1. ping 패킷 만들기
 
    ping := &protocol.CS_Ping{
        Time: time.Now().UnixMilli(),
    }
 
    fmt.Println("만들어진 핑 : ", ping)
 
    // 2. 패킷을 직렬화 (struct -> []byte)
 
    data, err := proto.Marshal(ping)
    if err != nil {
        panic(err)
    }
    fmt.Println("직렬화된 핑 : ", data)
 
  
    // 3. 직렬화 된 패킷을 역직렬화 ([]byte -> struct)
 
    var decoded protocol.CS_Ping
    err = proto.Unmarshal(data, &decoded)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("역직렬화 된 핑 : ", decoded)
}
  • 참고 : Go에서 := 연산자는 “지역” 내에서만 가능함!

  • 참고 2 : var 변수명 형식명 으로 변수 선언 가능함.

  • Go 파일 실행하는 방법

// main.go 있는 데에서 실행하면
go run ./server

에러가 뜨면서 안됨

  • no required module provides package 어쩌구
  • 패키지가 없다는 의미
  • go.mod 있는 곳으로 가서 아래 명령어 실행
go mod tidy

  • not in std 어쩌구
  • protocol 모듈을 못 찾았다는 의미

protobuf로 정의한 패킷 만들어서 뜯어보기 성공!

패킷을 추상화 하기

  • 모든 메시지를 하나의 형태로 일단 정의를 해서, 패킷의 타입에 따라 분기할 수 있도록 만듬
  • 이전에 컴공 캡스톤디자인 할 때 만들었던 통신 프로토콜이 이렇게 생겼었음

  • 여기서 말하는 커맨드가 패킷 타입. 아래의 사진처럼 만들려고 하는 것

 
/* ===================
    메시지 타입
   =================== */
 
enum MessageType {
    MESSAGE_TYPE_UNSPECIFIED = 0;
 
    PING = 1;
    PONG = 2;
 
    // 추후 확장 가능
}
 
/* ===================
    공통 패킷
   =================== */
 
message Packet {
    MessageType type = 1;
    bytes payload = 2;
}
 
/* ===================
    실제 메시지들
   =================== */
 
message Ping {
    int64 timestamp = 1;
}
 
message Pong {
    int64 timestamp = 1;
}
// 추상화 한 패킷을 뜯어보기
 
 
func main() {
 
    // 1. Ping 메시지 만들기
 
    ping := &protocol.Ping{
        Timestamp: time.Now().UnixMilli(),
    }
    
    // 2. Ping 을 []byte로 만들기
 
    payload, err := proto.Marshal(ping)
    if err != nil {
        panic(err)
    }
 
    // 3. []byte 로 만든 Ping을 공통 패킷으로 감싸기
 
    packet := &protocol.Packet{
        Type:    protocol.MessageType_PING,
        Payload: payload,
    }
 
    // 4. 감싼 공통 패킷을 직렬화 (실제 네트워크로 보내지는건 이게 보내짐)
 
    data, err := proto.Marshal(packet)
    if err != nil {
        panic(err)
    }
 
    // ==== 서버가 해당 핑 메시지를 받았다고 치고 처리해보기 ====
 
    var recvPacket protocol.Packet
 
    err = proto.Unmarshal(data, &recvPacket)
 
    if err != nil {
 
        panic(err)
 
    }
 
    switch recvPacket.Type {
    case protocol.MessageType_PING:
        var recvPing protocol.Ping
        _ = proto.Unmarshal(recvPacket.Payload, &recvPing)
 
 
        fmt.Println("받은 핑 : ", recvPing.Timestamp)
 
    default:
        fmt.Println("모르는 메시지 타입이 들어옴.")
    }
}
 
  • 비유를 하자면, 배달을 시켰다고 가정하자.

  • 실제로 배달이 온 음식이 payload, 배달 영수증이 MessageType, 이걸 다 감싸서 온 Packet이 전체 배달 봉지 쯤 될 듯.

  • 음식점 (서버) 에서 배달 보내기 위해 음식 (payload)을 준비하고, 영수증 (MessageType)을 앞에 붙인 다음에 이걸 비닐봉지(Packet)로 감싸서(Marshal, 직렬화) 보냄.

  • 그럼 주문자 (클라이언트)는 이걸 받아서 포장의 역순으로 까서(Unmarshal, 역직렬화) 확인하면 됨.

  • 이정도면 된다고 생각했는데, 다음 단계로 알아야 할 게 있었다.

  • 그렇다. 분할로 음식을 보낼 수도 있던 것이었다!

다음에 할 것

  • 길이 프레이밍에 대해 알아보기