Implement a Bi-Directional Streaming RPC for a Real-time Chat Application in Go
This challenge focuses on building a real-time chat application feature using Go's gRPC library. You will create a bi-directional streaming RPC that allows multiple clients to send and receive messages concurrently, simulating a multi-user chat room. This is a fundamental pattern for applications requiring real-time data exchange.
Problem Description
Your task is to implement a gRPC service in Go that supports bi-directional streaming for a chat application. This means that a single RPC call will allow both the client and the server to send streams of messages to each other simultaneously.
Key Requirements:
- Define Protobuf Service: Create a
.protofile that defines a service with a bi-directional streaming RPC method. This method should accept a stream of chat messages from the client and send a stream of chat messages back to the client. - Server Implementation:
- Implement the gRPC server in Go.
- The server should accept incoming connections from multiple clients.
- When a client connects, the server should receive messages from that client and broadcast them to all other connected clients.
- The server should also handle client disconnections gracefully.
- Client Implementation:
- Implement a gRPC client in Go.
- The client should be able to connect to the server.
- The client should be able to send messages to the server.
- The client should be able to receive broadcasted messages from the server and display them.
- Message Structure: Define a clear message structure (using Protobuf) for chat messages, which should include at least a sender's name/ID and the message content.
Expected Behavior:
- When Client A sends a message, Server should receive it and broadcast it to Client B, Client C, etc.
- Client B, Client C, etc., should receive the message sent by Client A.
- Each client should be able to send messages independently and receive messages from other clients without interruption.
- The server should keep track of connected clients.
Edge Cases to Consider:
- Multiple simultaneous connections: The server must handle numerous clients connecting and sending messages concurrently.
- Client disconnects: How does the server handle a client abruptly disconnecting?
- Empty messages: Should empty messages be allowed? If so, how are they handled?
Examples
Let's consider a simple scenario with two clients.
Example 1: Basic Message Exchange
// Client 1 sends "Hello everyone!"
// Server receives and broadcasts to Client 2.
// Client 2 receives "Client 1: Hello everyone!"
// Client 2 sends "Hi Client 1!"
// Server receives and broadcasts to Client 1.
// Client 1 receives "Client 2: Hi Client 1!"
Explanation: This demonstrates the core bi-directional streaming. Client 1 sends a message, which is routed through the server to Client 2. Then, Client 2 sends a message, which is routed back to Client 1.
Example 2: Handling Multiple Clients
Imagine three clients: Alice, Bob, and Charlie.
// Alice sends "Good morning!"
// Server broadcasts to Bob and Charlie.
// Bob receives "Alice: Good morning!"
// Charlie receives "Alice: Good morning!"
// Bob sends "Hello Alice and Charlie!"
// Server broadcasts to Alice and Charlie.
// Alice receives "Bob: Hello Alice and Charlie!"
// Charlie receives "Bob: Hello Alice and Charlie!"
Explanation: This shows how the server acts as a hub, broadcasting messages from one client to all other connected clients.
Constraints
- Protobuf Version: Use Protobuf version 3 (
proto3). - gRPC Version: Use the latest stable version of gRPC for Go.
- Concurrency: The server must be able to handle at least 100 concurrent client connections and message exchanges without significant latency.
- Error Handling: Implement robust error handling for network issues, invalid messages, and server-side errors.
- Message Content: Message content can be up to 256 characters long.
- Sender Name: Sender names are alphanumeric and up to 32 characters long.
Notes
- You will need to define your
.protofile first, compile it to generate Go code, and then implement the server and client logic. - Consider using Goroutines on the server-side to handle each client's stream independently.
- Think about how you will manage the collection of active client streams on the server to enable broadcasting.
- For a real-world application, you'd likely add more features like user authentication, private messages, etc., but this challenge focuses on the core streaming mechanism.
- Success is defined by successfully establishing a connection, sending messages from multiple clients, and having those messages correctly broadcasted to all other connected clients in real-time.