Search code examples
pythonsocketsthrift

Thrift in python, client of simple example can not connect to local host on Ubuntu 14.04 LTS


I am trying to learn how Thrift(version 0.9.2) works in python with a simple example. The server code works fine, but running the client code gives the error Could not connect to localhost:9090, and I tried the shell commands

netstat -nap | grep 9090, this outputs

tcp 0 0 0.0.35.130:9090 0.0.0.0:* LISTEN 4656/python,

and command

nc -zv localhost 9090 which outputs

nc: connect to localhost port 9090 (tcp) failed: Connection refused.

At this point I am not sure which part (the computer itself, Thrift, or the code?) has gone wrong. All the code is given as following, would anyone point out where the mistake is?

Below is the 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)
}

and the server code is,

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()

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

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

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

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

and this is the client,

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', 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 = 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)

Solution

  • I think the problem is with your call -

    transport = TSocket.TServerSocket('9090')
    

    This should be

    transport = TSocket.TServerSocket(host='localhost', port=9090) 
    

    or

    transport = TSocket.TServerSocket(port=9090)
    

    Actually - port argument is not even required. If you don't give, it's default is 9090. Your code is saying host is 9090

    This can be clear from the netstat -nap output. The line indeed shows 'something' listening on port 9090 (that is because the default port in thrift TServerSocket is 9090), but check the listening address, it is 0.0.35.130. This should be 0.0.0.0 for any interface or 127.0.0.1 for localhost.

    Edit:

    In fact if you do a socket.getaddrinfo('9090', 9090). It does indeed show an address of 0.0.35.130, so what you see in netstat is not surprising.

    Your nc output is also saying nothing is listening on localhost:9090 (by the Connection Refused Error).

    The above fix should fix the problem.