杰瑞科技汇

thrift python server

Of course! Here is a comprehensive guide on how to create a Thrift server in Python, including a complete, step-by-step example.

thrift python server-图1
(图片来源网络,侵删)

What is Thrift?

Apache Thrift is a binary serialization protocol and a Remote Procedure Call (RPC) framework. It allows you to define data types and service interfaces in a simple language-agnostic definition file (.thrift). This file is then used to generate code for many different programming languages (Python, Java, C++, Go, etc.), enabling seamless communication between services written in different languages.


Step 1: Install Necessary Libraries

First, you need to install the Thrift compiler and the Python Thrift library.

  1. Install the Thrift Compiler: This is a separate binary that you install on your system. You can download it from the Apache Thrift download page or use a package manager.

    • On macOS (using Homebrew):
      brew install thrift
    • On Debian/Ubuntu:
      sudo apt-get install thrift
    • On Windows: Download the binary from the website and add it to your system's PATH.
  2. Install the Python Thrift library: This is the library your Python code will use to run the server and client.

    thrift python server-图2
    (图片来源网络,侵删)
    pip install thrift

Step 2: Define the Service Interface (.thrift file)

Create a file named calculator.thrift. This file will define the data structures and the methods your server will expose.

calculator.thrift

// Define the namespace for the generated Python code
namespace py calculator
// Define a simple exception
exception InvalidOperation {
  1: i32 what,
  2: string why
}
// Define a struct to hold operation results
struct Work {
  1: i32 num1,
  2: i32 num2,
  3: Operation op,
  4: optional string comment
}
// Define an enumeration for operations
enum Operation {
  ADD = 1,
  SUBTRACT = 2,
  MULTIPLY = 3,
  DIVIDE = 4
}
// This is the main service interface
service Calculator {
  // A simple ping to check if the server is alive
  void ping(),
  // Perform a calculation
  i32 calculate(1:i32 num1, 2:i32 num2, 3:Operation op) throws (1:InvalidOperation ouch),
  // Process a work struct and return a string result
  string getStruct(1:Work work),
  // A method that doesn't take any arguments
  i32 getCounter(),
}

Step 3: Generate Python Code from the .thrift File

Now, use the Thrift compiler to turn your .thrift definition into Python code.

Run the following command in your terminal in the same directory as calculator.thrift:

thrift --gen py calculator.thrift

This will create a new directory called gen-py. Inside, you'll find the generated Python files and a directory for your service (calculator).

Your project structure should now look like this:

.
├── calculator.thrift
└── gen-py
    └── calculator
        ├── Calculator.py
        ├── __init__.py
        ├── constants.py
        └── ttypes.py
  • ttypes.py: Contains the generated code for your data types (Work, Operation, InvalidOperation).
  • Calculator.py: Contains the service interface definition (Calculator) and the base class for your server implementation (Calculator).

Step 4: Create the Python Server Implementation

This is the core of your server. You'll create a Python class that inherits from the generated Calculator server base class and implement its methods.

Create a new file named server.py:

server.py

import sys
import time
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.server import TServer
# Import the generated code
from gen_py.calculator import Calculator
from gen_py.calculator.ttypes import Work, Operation, InvalidOperation
# Create a class that implements the Calculator service
class CalculatorHandler:
    def __init__(self):
        self.counter = 0
    def ping(self):
        print("ping()")
    def calculate(self, num1, num2, op):
        print(f"calculate({num1}, {num2}, {op})")
        self.counter += 1
        if op == Operation.ADD:
            val = num1 + num2
        elif op == Operation.SUBTRACT:
            val = num1 - num2
        elif op == Operation.MULTIPLY:
            val = num1 * num2
        elif op == Operation.DIVIDE:
            if num2 == 0:
                raise InvalidOperation(what=101, why="Cannot divide by zero")
            val = num1 // num2 # Using integer division
        else:
            raise InvalidOperation(what:100, why="Invalid operation")
        return val
    def getStruct(self, work):
        print(f"getStruct({work})")
        # You can access struct fields like work.num1, work.op, etc.
        return f"Work struct received: num1={work.num1}, op={work.op}, comment='{work.comment or 'N/A'}'"
    def getCounter(self):
        print(f"getCounter() -> {self.counter}")
        return self.counter
def main():
    # Create a handler to process the RPC calls
    handler = CalculatorHandler()
    processor = Calculator.Processor(handler)
    # Create a TCP socket and listen on port 9090
    transport = TSocket.TServerSocket(port=9090)
    # Use a buffered transport
    tfactory = TTransport.TBufferedTransportFactory()
    # Use a binary protocol
    pfactory = Thrift.TBinaryProtocol.TBinaryProtocolFactory()
    # Create a multi-threaded server to handle concurrent clients
    server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
    print('Starting the server...')
    try:
        server.serve()
    except KeyboardInterrupt:
        print('Stopping the server...')
        server.stop()
if __name__ == '__main__':
    main()

Step 5: Create a Python Client (To Test the Server)

To see if your server works, you need a client. Create a file named client.py in the same directory.

client.py

import sys
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
# Import the generated code
from gen_py.calculator import Calculator
from gen_py.calculator.ttypes import Work, Operation, InvalidOperation
def main():
    # Make socket
    transport = TSocket.TSocket('localhost', 9090)
    # Buffering is critical. Raw sockets are very slow
    transport = TTransport.TBufferedTransport(transport)
    # Wrap in a protocol
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    # Create a client to use the protocol encoder
    client = Calculator.Client(protocol)
    # Connect!
    transport.open()
    print("Client connected. Testing server...")
    # Test ping
    client.ping()
    print("ping() successful")
    # Test calculate
    try:
        sum_result = client.calculate(5, 10, Operation.ADD)
        print(f"5 + 10 = {sum_result}")
        divide_result = client.calculate(20, 5, Operation.DIVIDE)
        print(f"20 / 5 = {divide_result}")
        # This will raise an exception
        client.calculate(5, 0, Operation.DIVIDE)
    except InvalidOperation as e:
        print(f"Caught InvalidOperation: {e.why} (code: {e.what})")
    # Test getStruct
    work = Work(num1=15, num2=3, op=Operation.MULTIPLY, comment="This is a test multiplication")
    result = client.getStruct(work)
    print(result)
    # Test getCounter
    counter_val = client.getCounter()
    print(f"Current counter value: {counter_val}")
    client.calculate(1, 1, Operation.ADD) # Increment the counter
    counter_val = client.getCounter()
    print(f"Current counter value after increment: {counter_val}")
    # Close!
    transport.close()
if __name__ == '__main__':
    main()

Step 6: Run the Server and Client

  1. Start the Server: Open a terminal and run:

    python server.py

    You should see the output:

    Starting the server...
  2. Run the Client: Open a new terminal (leave the server running) and run:

    python client.py

    You will see the client's output, and the server's terminal will show the log of the methods being called:

    Client Output:

    
    Client connected. Testing server...
    ping() successful
    5 + 10 = 15
    20 /
分享:
扫描分享到社交APP
上一篇
下一篇