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 definitionserver.py- Server implementationclient.py- Client implementationdemo_part1.py- Test/demo script
📹 Demo Video (1 minute):
Show:
- Starting the server
- Running the client
- 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
.protofile - Not starting the server before running the client
- Incorrect port numbers in client/server
Debugging
Enable gRPC logging to see what's happening:
Next Steps
Once Part 1 is complete, proceed to Part 2: Failure Handling where you'll add timeout handling and retry logic.