---
# System prepended metadata

title: gRPC
tags: [gPRC, python, kotlin]

---

# gRPC
###### tags: `gPRC` `python` `kotlin`
gRPC主要是一個透過http/2來通訊的遠端呼叫程式，透過google發明的proto buffer語言來描述資料結構，再折成各個語言的形狀。


不得不說上手挺容易的
首先看一下proto檔案
```protobuf=
syntax = "proto3";
// 下面這個是我為了介接kotlin所用的
option java_multiple_files = true;
option java_package = "io.quarkus.example";
option java_outer_classname = "HelloWorldProto";
    
package helloworld;
    
service Greeter {
    // 你想使用的方法
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 資料結構，後面的數字是為了防止打亂資料結構所給的資料順序
message HelloRequest {
    string name = 1;
}
message HelloReply {
    string message = 1;
}
```

## Server

寫好proto檔案後可以讓他自動跑出來對應語言的程式，以py來說是
```bash=
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./helloworld.proto
```
那些點可以視作在你現在的位置。

輸入之後會出現兩個檔案

```
hellowoeld_pb2_grpc.py
hellowoeld_pb2.py
```

再來創建一個service.py檔案

```python=
from proto.helloworld_pb2_grpc import GreeterServicer, add_GreeterServicer_to_server
from proto.helloworld_pb2 import HelloReply
import grpc
import logging
import asyncio
    
class HelloService(GreeterServicer):
    def SayHello(self, request, context):
        name = request.name # 從client端發來的request，裡面name的資料
        print(context.peer()) # 這個可以偷看client IP
        return HelloReply(message=f"Hello {name}")
    
    async def serve():
        server = grpc.aio.server()
        add_GreeterServicer_to_server(HelloService(), server)
        server.add_insecure_port("[::]:50051")
        await server.start()
        await server.wait_for_termination()
    
    if __name__ == "__main__":
        logging.basicConfig(level=logging.INFO)
        asyncio.run(serve())
```

再來只要

```bash=
python service.py
```

就可以開始你的gRPC的server端了


---
## Client

另一邊用kotlin來展示
proto檔案一樣用上面那個
使用maven實作
```bash=
mvn compile
```
只要這樣maven就會幫你直接轉換
資料會在
```
target
  ｜_gemerated-sources
        |_grpc
```

這裡面

再來在你的專案內創造一個HelloResource.kt
```kotlin=
import javax.inject.Inject
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.PathParam
import javax.ws.rs.Produces
import javax.ws.rs.core.MediaType
    
@Path("/hello")
class HelloResource {
    @Inject
    @GrpcService("hello")
    var client: GreeterBlockingStub? = null
    
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    fun hello(): String {
        return "hello"
    }
    
    @GET
    @Path("/{name}")
    fun hello(@PathParam("name") name: String?): String {
        return client!!.sayHello(HelloRequest.newBuilder().setName("name").build()).message
        }
    }
    // 這是以一個param直接傳遞資料的形式，做成為服務可以不用給router。
```

另外要binding port，在你的application.properties裡面加入
```
quarkus.grpc.clients.hello.host = localhost
quarkus.grpc.clients.hello.port = 50051
```
再來只要
```bash=
$ mvn compile quarkus:dev
```
就可以在localhost:50051/hello/quarkus內看到
```
Hello quarkus
```