ingressu.com

Implementing a Chat Service with Bidirectional Streaming gRPC in Golang

Written on

Chapter 1: Introduction

This article will guide you through the process of building a chat service utilizing bidirectional streaming gRPC with Golang. We'll also explore how to verify the implementation using grpcui and unit tests.

Bidirectional Streaming gRPC Overview

Bidirectional streaming gRPC allows both the client and server to send a series of messages through a read-write stream. Each stream operates independently, enabling clients and servers to read and write messages in any order. In a bidirectional streaming gRPC call, both parties can send multiple messages to each other and can stop sending or receiving messages at any time, potentially triggering various business logic or errors.

The format for this communication is "RPC streaming requests yield RPC streaming responses." Below is a visual representation of how bidirectional streaming RPC functions.

Diagram illustrating bidirectional streaming RPC

Chapter 2: Building the Bidirectional Streaming gRPC

In a previous article, I outlined the creation of a client streaming gRPC. For this project, the goal is to implement two bidirectional streaming gRPC services for chat functionality: one using byte data and the other using string data. Both implementations will be accompanied by unit tests and verified using grpcui.

Let's dive into the process.

Step 1: Folder Structure

Create a directory named clientstream. The name bidirectstream denotes the type of gRPC, but you can choose any name you prefer. While Golang typically suggests using concise names without capital letters or underscores, I opted for a name that aligns with the gRPC type.

Step 2: Set Up Directories

Create the following folders within your project:

  • proto
  • client
  • server

Once completed, your folder structure should resemble the image below.

Step 3: Create and Populate the Proto File

Create a proto file named bidirectstream.proto in the proto folder. This name also reflects the gRPC type.

After creating the bidirectstream.proto, fill it with the following content:

syntax = "proto3";

option go_package = "alltypes/bidirectstream/proto";

package pb;

service Phone {

rpc SendMsgBytes(stream SendMsgBytesRequest) returns (stream SendMsgBytesResponse) {}

rpc SendMsgStr(stream SendMsgStrRequest) returns (stream SendMsgStrResponse) {}

}

message SendMsgBytesRequest {

bytes msg = 1;

}

message SendMsgBytesResponse {

bytes msg = 1;

}

message SendMsgStrRequest {

string msg = 1;

}

message SendMsgStrResponse {

string msg = 1;

}

Step 4: Generate pb.go Files

Open your terminal and execute the following command to automatically generate pb.go files:

% protoc --go_out=. --go-grpc_opt=require_unimplemented_servers=false --go_opt=paths=source_relative

--go-grpc_out=. --go-grpc_opt=paths=source_relative

proto/bidirectstream.proto

After running the command, you will see newly generated files: bidirectstream.pb.go and bidirectstream_grpc.pb.go. Do not modify these files directly; instead, make changes to the bidirectstream.proto file and re-run the command to regenerate the files.

Step 5: Create the Server

Navigate to the server folder and create a file named server.go. The next steps include creating a phoneServer struct and implementing the required methods.

  1. Define the Phone Server Struct: The phoneServer struct is created from the automatically generated bds.PhoneServer interface.
  2. Set Up a TCP Listener: In server.go, establish a listener on TCP port 50058.
  3. Log Server Start: Implement a log statement indicating that the server has started.
  4. Register the Server: Create a new gRPC server instance and register the phoneServer with it.
  5. Implement gRPC Methods: Implement the methods SendMsgBytes and SendMsgStr for processing incoming messages.

The complete code for server.go is as follows:

package main

import (

"errors"

"io"

"log"

"net"

"strings"

"time"

bds "github.com/ramseyjiang/go_mid_to_senior/pkgusages/grpc/alltypes/bidirectstream/proto"

"google.golang.org/grpc"

"google.golang.org/grpc/reflection"

)

type phoneServer struct {

bds.PhoneServer

calls []string

}

func main() {

listener, err := net.Listen("tcp", "0.0.0.0:50058")

if err != nil {

_ = errors.New("failed to listen: the port")

}

log.Print("Server started")

s := grpc.NewServer()

bds.RegisterPhoneServer(s, &phoneServer{})

reflection.Register(s)

if err = s.Serve(listener); err != nil {

log.Fatalf("failed to serve: %v", err)

}

}

// Implement SendMsgBytes and SendMsgStr methods...

(Additional code for the methods would follow here, but has been omitted for brevity.)

Step 6: Verify the Server with grpcui

Once the server is running, you can verify it using grpcui. Open a new terminal window and execute:

% grpcui -plaintext 0.0.0.0:50058

This will open a browser window showing all your implemented gRPC methods.

Step 7: Unit Testing the Server

In the server folder, create a file named server_test.go to automate the verification of your server through unit tests. The complete content for server_test.go will include various test cases for SendMsgBytes and SendMsgStr.

(Refer to the original article for the complete testing code.)

Step 8: Implementing the Client

To create the client-side of the gRPC service, navigate to the client folder and create a client.go file. The client will connect to the server and send requests while receiving responses.

The main function in the client.go file will establish a connection to the server and invoke the chat methods.

package main

import (

"context"

"errors"

"io"

"log"

"time"

bds "github.com/ramseyjiang/go_mid_to_senior/pkgusages/grpc/alltypes/bidirectstream/proto"

"google.golang.org/grpc"

"google.golang.org/grpc/credentials/insecure"

)

func main() {

cc, err := grpc.Dial("localhost:50058", grpc.WithTransportCredentials(insecure.NewCredentials()))

if err != nil {

log.Fatalf("could not connect: %v", err)

}

defer cc.Close()

client := bds.NewPhoneClient(cc)

log.Println("Starting Bidirectional Stream Phone RPC...")

BidirectionalStreamSendBytesMsg(client)

BidirectionalStreamSendStrMsg(client)

}

// Implement BidirectionalStreamSendBytesMsg and BidirectionalStreamSendStrMsg methods...

(Additional code for the methods would follow here, but has been omitted for brevity.)

Step 9: Running the Client

Keep your server running and execute the following command to run the client:

% go run client/client.go

You should see the output reflecting both the client and server interactions.

Conclusion

In this article, we successfully implemented a bidirectional streaming gRPC service using Golang. I hope this guide helps you understand how to create a streaming gRPC server and client. Happy coding!

For those unfamiliar with gRPC, consider reading related articles on the topic for further learning.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Unlock Your Potential: Five Essential Skills for Life Improvement

Discover five key skills for personal growth and self-improvement that can elevate your life and help you navigate challenges effectively.

Understanding Your Inner Desires and Navigating Life's Flow

Explore how to recognize your inner desires and manage the emotional complexities that arise during periods of personal growth.

Clever Strategies to Outsmart Distractions and Tackle Procrastination

Discover effective techniques to combat procrastination and enhance your creative output with these eight clever strategies.

Exploring the Impact of Scents on Human Psychology

Discover the distinctions between aromacology and aromatherapy, and how scents influence human behavior and emotions.

Navigating Digital Transformation at Scale: A Comprehensive Guide

Explore how to effectively manage scalable digital transformation through a structured approach, comprehensive understanding, and right methodologies.

Exciting Insights on the Samsung Galaxy S24 Ultra Leak

Discover the latest rumors surrounding Samsung's Galaxy S24 Ultra, featuring design changes, camera upgrades, and anticipated release details.

Understanding Birth Biomechanics: The Harmonious Interaction of Maternal and Fetal Forces

Delve into the fascinating world of birth biomechanics and how it enhances the birthing experience for mothers and babies alike.

Revolutionizing Health: The Promise of Artificial Immune Systems

Explore how Artificial Immune Systems may transform healthcare by utilizing nanobots to combat illnesses and enhance recovery.