Skip to content

Part 1: Basic RPC Implementation

Weight: 30%

This part establishes the foundation for your RPC service.


Objectives

  • Set up a gRPC service using Protocol Buffers
  • Implement basic calculator operations
  • Establish client-server communication

Requirements

1. Use Provided Service Interface

DO NOT MODIFY

The calculator.proto file is provided as part of the assignment starter code. You must NOT modify this file. Use it exactly as provided.

Download the provided calculator.proto file from the starter code package. It defines:

syntax = "proto3";

package calculator;

service Calculator {
  rpc Add(BinaryOperation) returns (Result);
  rpc Subtract(BinaryOperation) returns (Result);
  rpc Multiply(BinaryOperation) returns (Result);
  rpc Divide(BinaryOperation) returns (Result);

  // Additional operations for later parts
  rpc IncrementCounter(CounterRequest) returns (CounterResult);
  rpc GetCounter(Empty) returns (CounterResult);
  rpc ResetCounter(Empty) returns (CounterResult);
}

message BinaryOperation {
  double a = 1;
  double b = 2;
}

message Result {
  double value = 1;
  string error = 2;
}

message CounterRequest {
  string request_id = 1;
  int32 increment = 2;
}

message CounterResult {
  int32 value = 1;
  bool was_duplicate = 2;
}

message Empty {}

For Part 1, you only need to implement the first 4 operations (Add, Subtract, Multiply, Divide).

2. Implement Server

Your server must:

  • ✅ Implement all four calculator operations
  • ✅ Handle division by zero gracefully
  • ✅ Return appropriate error messages
  • ✅ Run on port 50051

Implementation Structure:

class CalculatorServicer(calculator_pb2_grpc.CalculatorServicer):
    def Add(self, request, context):
        # TODO: Implement addition
        pass

    def Subtract(self, request, context):
        # TODO: Implement subtraction
        pass

    def Multiply(self, request, context):
        # TODO: Implement multiplication
        pass

    def Divide(self, request, context):
        # TODO: Check for division by zero
        # TODO: Set appropriate error code if b is zero
        # TODO: Otherwise perform division
        pass

3. Implement Client

Your client must:

  • ✅ Connect to the server
  • ✅ Make RPC calls for all operations
  • ✅ Display results to the user
  • ✅ Handle server errors gracefully

Example Client Usage:

def main():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = calculator_pb2_grpc.CalculatorStub(channel)

        # Make RPC call
        response = stub.Add(calculator_pb2.BinaryOperation(a=10, b=5))
        print(f"10 + 5 = {response.value}")

Testing Requirements

Test Cases

Your implementation must pass these test cases:

Operation Input Expected Output
Add a=10, b=5 15.0
Subtract a=10, b=5 5.0
Multiply a=10, b=5 50.0
Divide a=10, b=5 2.0
Divide a=10, b=0 Error: Division by zero

Demo Script

Create a script that demonstrates all operations:

def demo_basic_operations():
    """Demonstrate basic calculator operations."""
    operations = [
        ("Add", 10, 5),
        ("Subtract", 10, 5),
        ("Multiply", 10, 5),
        ("Divide", 10, 5),
        ("Divide", 10, 0),  # Error case
    ]

    for op_name, a, b in operations:
        # Make RPC call and display result
        pass

Deliverables

📦 Code Files:

  • calculator.proto - Service definition
  • server.py - Server implementation
  • client.py - Client implementation
  • demo_part1.py - Test/demo script

📹 Demo Video (1 minute):

Show:

  1. Starting the server
  2. Running the client
  3. All operations working (including error case)

Grading Rubric

Criterion Points Description
Protocol Buffer Definition 5 Correct .proto file with all operations
Server Implementation 10 All operations work correctly
Error Handling 5 Division by zero handled properly
Client Implementation 5 Successfully makes RPC calls
Code Quality 3 Clean, readable, documented code
Demo 2 Clear demonstration of functionality
Total 30

Tips

Start Simple

Get one operation (e.g., Add) working end-to-end before implementing the others.

Common Pitfalls

  • Forgetting to regenerate Python code after modifying .proto file
  • Not starting the server before running the client
  • Incorrect port numbers in client/server

Debugging

Enable gRPC logging to see what's happening:

import logging
logging.basicConfig(level=logging.DEBUG)


Next Steps

Once Part 1 is complete, proceed to Part 2: Failure Handling where you'll add timeout handling and retry logic.


Resources