0

I started to use Pyro4 from yesterday, so I'm experimenting the tutorial code from the official document. Everything ran perfectly locally, but I encountered problems when I adapt these examples in different machines, specifically, the stockmarket example. So here is my adapted code on server and client.
==== Server Side ====
stockmarket.py

from __future__ import print_function
import random
import threading
import time
import Pyro4

class StockMarket(object):
    def __init__(self, marketname, symbols):
        self.name = marketname
        self.symbolmeans = {}
        for symbol in symbols:
            self.symbolmeans[symbol] = random.uniform(20, 200)
        self.aggregators = []

    def generate(self):
        quotes = {}
        for symbol, mean in self.symbolmeans.items():
            if random.random() < 0.2:
                quotes[symbol] = round(random.normalvariate(mean, 20), 2)
        print("new quotes generated for", self.name)
        for aggregator in self.aggregators:
            aggregator.quotes(self.name, quotes)

    def listener(self,aggregator):
        print("market {0} adding new aggregator".format(self.name))
        self.aggregators.append(aggregator)

    def symbols(self):
        return list(self.symbolmeans.keys())

    def run(self):
        def generate_symbols():
            while True:
                time.sleep(random.random())
                self.generate()
        thread = threading.Thread(target=generate_symbols)
        thread.setDaemon(True)
        thread.start()

def main():
    nasdaq = StockMarket("NASDAQ", ["AAPL", "CSCO", "MSFT", "GOOG"])
    newyork = StockMarket("NYSE", ["IBM", "HPQ", "BP"])

    daemon = Pyro4.Daemon("159.8.183.94")
    nasdaq_uri = daemon.register(nasdaq, "nasdaq")
    newyork_uri = daemon.register(newyork, "newyork")
    ns = Pyro4.locateNS()
    ns.register("example.stockmarket.nasdaq", nasdaq_uri)
    ns.register("example.stockmarket.newyork", newyork_uri)
    nasdaq.run()
    newyork.run()
    print("Stockmarkets running.")
    daemon.requestLoop()

if __name__ == "__main__":
    main()

aggregator.py

from __future__ import print_function
import Pyro4

class Aggregator(object):
    def __init__(self):
        self.viewers = {}
        self.symbols = []
    def add_symbols(self, symbols):
        self.symbols.extend(symbols)

    def available_symbols(self):
        return self.symbols

    def view(self, viewer, symbols):
        print("aggregator gets a new viewer, for symbols:", symbols)
        self.viewers[viewer] = symbols

    def quotes(self, market, stockquotes):
        print (market)
        print (stockquotes)
        for symbol, value in stockquotes.items():
            for viewer, symbols in self.viewers.items():
                if symbol in symbols:
                    viewer.quote(market, symbol, value)


def main():
    aggregator = Aggregator()
    daemon = Pyro4.Daemon(host="159.8.183.94")
    agg_uri = daemon.register(aggregator, "aggregator")
    ns = Pyro4.locateNS()
    ns.register("example.stockquote.aggregator", agg_uri)
    for market, market_uri in ns.list(prefix="example.stockmarket.").items():
        print("joining market", market)
        stockmarket = Pyro4.Proxy(market_uri)
        stockmarket.listener(aggregator)
        aggregator.add_symbols(stockmarket.symbols())
    if not aggregator.available_symbols():
        raise ValueError("no symbols found! (have you started the stock market first?)")
    print("Aggregator running. Symbols:", aggregator.available_symbols())
    daemon.requestLoop()

if __name__ == "__main__":
    main()

==== Client Side ====
viewer.py

from __future__ import print_function
import sys
import Pyro4

if sys.version_info < (3,0):
    input = raw_input


class Viewer(object):
    def quote(self, market, symbol, value):
        print("{0}.{1}: {2}".format(market, symbol, value))


def main():
    viewer = Viewer()
    daemon = Pyro4.Daemon()
    daemon.register(viewer)
    ns = Pyro4.locateNS(host="159.8.183.94", port=8080)
    aggregator_uri = ns.lookup("example.stockquote.aggregator")
    print ("aggregator uri is ", aggregator_uri)
    aggregator = Pyro4.Proxy(aggregator_uri)
    print("Available stock symbols:", aggregator.available_symbols())
    symbols = input("Enter symbols you want to view (comma separated):")
    symbols = [symbol.strip() for symbol in symbols.split(",")]
    aggregator.view(viewer, symbols)
    print("Viewer listening on symbols", symbols)
    daemon.requestLoop()

if __name__ == "__main__":
    main()

==== How I run the code ====
On server machine, I ran the following code to define name server

python -m Pyro4.naming --host 159.8.183.94 --port 8080

Then I ran stockmarket.py and aggregator.py, everything is fine so far. Afer that, I started viewer.py, type the symbols I want to see, then I observe an error from stockmarket.py

Exception in thread Thread-18:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "stockmarket.py", line 37, in generate_symbols
    self.generate()
  File "stockmarket.py", line 24, in generate
    aggregator.quotes(self.name, quotes)
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 171, in __call__
    return self.__send(self.__name, args, kwargs)
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 410, in _pyroInvoke
    msg = message.Message.recv(self._pyroConnection, [message.MSG_RESULT], hmac_key=self._pyroHmacKey)
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/message.py", line 168, in recv
    msg = cls.from_header(connection.recv(cls.header_size))
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/socketutil.py", line 448, in recv
    return receiveData(self.sock, size)
  File "/usr/local/lib/python2.7/dist-packages/Pyro4/socketutil.py", line 182, in receiveData
    raise err
ConnectionClosedError: receiving: not enough data

I think it's only a small bug in my code, and I've been stuck here for several hours, any suggestions or help will be very appreciated!! Thanks!!

James Guo
  • 53
  • 2
  • 9

1 Answers1

0

The code as posted works fine, I'm running it on my machine without problems. Ofcourse I've replaced your IP address with the hostname of my machine.

So it's a problem of your network setup, or a difference in software configuration on your server and client machines.

To rule out any problems with the network, have you tried to run it all on the same machine (the server)? Is the problem only with the viewer (meaning: after starting just the stockmarket and aggregator, are they printing stock tickers without errors?)

Also, enable debug logging and see if you can find anything useful in the logs that Pyro produces. Maybe it will point you to the problem. Have a look at http://pythonhosted.org/Pyro4/tipstricks.html#logging

Finally - you really have to provide more information to be able to even begin figuring out what could be the issue. What OS are you using on server and client? What Python and Pyro versions on server and client? etc.

Irmen de Jong
  • 2,739
  • 1
  • 14
  • 26