Tuesday, July 13, 2010

Thrift Server-Client in Python

1. Write Thrift stub code

[tkang@neb005 thrift]$ vi helloworld.thrift


const string HELLO_IN_KOREAN = "an-nyoung-ha-se-yo"
const string HELLO_IN_FRENCH = "bonjour!"
const string HELLO_IN_JAPANESE = "konichiwa!"

service HelloWorld {
void ping(),
i32 sayHello(),
i32 sayMsg(1:string msg)
}


2. Generate python code

[tkang@neb005 thrift]$ thrift --gen py helloworld.thrift

Generated codes will be saved under "gen-py" directory.
[tkang@neb005 thrift]$ ls
gen-py helloworld.thrift

3. Fill in Server code

[tkang@neb005 thrift]$ mkdir py-impl
[tkang@neb005 thrift]$ cd py-impl
[tkang@neb005 py-impl]$ vi PythonServer.py


#!/usr/bin/env python

import sys
sys.path.append('../gen-py')

from helloworld import HelloWorld
from helloworld.ttypes import *

from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer

import socket

class HelloWorldHandler:
def __init__(self):
self.log = {}

def ping(self):
print "ping()"

def sayHello(self):
print "sayHello()"
return "say hello from " + socket.gethostbyname(socket.gethostname())

def sayMsg(self, msg):
print "sayMsg(" + msg + ")"
return "say " + msg + " from " + socket.gethostbyname(socket.gethostname())

handler = HelloWorldHandler()
processor = HelloWorld.Processor(handler)
transport = TSocket.TServerSocket(30303)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()

server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

print "Starting python server..."
server.serve()
print "done!"


4. Write Client code to connect to server

[tkang@neb005 py-impl]$ vi PythonClient.py


#!/usr/bin/env python

import sys
sys.path.append('../gen-py')

from helloworld import HelloWorld
from helloworld.ttypes import *
from helloworld.constants import *

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

try:
# Make socket
transport = TSocket.TSocket('localhost', 30303)

# 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 = HelloWorld.Client(protocol)

# Connect!
transport.open()

client.ping()
print "ping()"

msg = client.sayHello()
print msg
msg = client.sayMsg(HELLO_IN_KOREAN)
print msg

transport.close()

except Thrift.TException, tx:
print "%s" % (tx.message)

4 comments:

bobuss said...

my first attempt with thrift. Thanks, except :

transport = TSocket.TServerSocket(port=30303)
in the server

and

the types in the thrift declaration
string sayHello(),
string sayMsg(1:string msg)

Tomasz Ducin said...

This is a very good post :-) thanks!

Jamil Atta said...

Some time the method socket.gethostbyname(hostname) can not work, so use the socket.gethostname() the difference is that will print the name otherwise the IP.

Sergey Kostin said...

Having a problem with server.

./PythonServer.py localhost
Starting python server...
Traceback (most recent call last):
File "./PythonServer.py", line 40, in
server.serve()
File "/usr/lib64/python2.7/site-packages/thrift/server/TServer.py", line 77, in serve
self.serverTransport.listen()
File "/usr/lib64/python2.7/site-packages/thrift/transport/TSocket.py", line 152, in listen
res0 = self._resolveAddr()
File "/usr/lib64/python2.7/site-packages/thrift/transport/TSocket.py", line 39, in _resolveAddr
socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
TypeError: getaddrinfo() argument 1 must be string or None