Currently, I have an application that has two servers: the first processes orders and responds individually, the second broadcasts results to other interested subscribers. They need to be served from different ports. I can start() both of them, but I can only get one or the other to serve_forever() as I read it is a blocking function. I am looking for ideas on how to keep both the servers from exiting. abbreviated code below:

def main():
    stacklist = []
    subslist = []
    stacklist.append(CreateStack('stuff'))
    subslist.append(Subscription('stuff'))
    bcastserver = BroadcastServer(subslist) # creates a new server
    tradeserver = TradeServer(stacklist) # creates a new server
    bcastserver.start() # start accepting new connections
    tradeserver.start() # start accepting new connections
    #bcastserver.serve_forever()  #if I do it here, the first one...
    #tradeserver.serve_forever()  #blocks the second one

class TradeServer(StreamServer):
    def __init__(self, stacklist):
        self.stacklist = stacklist
        StreamServer.__init__(self, ('localhost', 12345), self.handle)
        #self.serve_forever()  #If I put it here in both, neither works

    def handle(self, socket, address):
        #handler here

class BroadcastServer(StreamServer):
    def __init__(self, subslist):
        StreamServer.__init__(self, ('localhost', 8000), self.handle)
        self.subslist = subslist
        #self.serve_forever()  #If I put it here in both, neither works

    def handle(self, socket, address):
        #handler here

Perhaps I just need a way to keep the two from exiting, but I'm not sure how. In the end, I want both servers to listen forever for incoming connections and handle them.

有帮助吗?

解决方案 2

ok, I was able to do this using threading and with gevent's monkeypatch library:

from gevent import monkey
def main():
    monkey.patch_thread()
# etc, etc
t = threading.Thread(target=bcastserver.serve_forever)
t.setDaemon(True)
t.start()
tradeserver.serve_forever()

其他提示

I know this question has an accepted answer, but there is a better one. I'm adding it for people like me who find this post later.

As described on in the gevent documentation about servers:

The BaseServer.serve_forever() method calls BaseServer.start() and then waits until interrupted or until the server is stopped.

So you can just do:

def main():
    stacklist = []
    subslist = []
    stacklist.append(CreateStack('stuff'))
    subslist.append(Subscription('stuff'))
    bcastserver = BroadcastServer(subslist) # creates a new server
    tradeserver = TradeServer(stacklist) # creates a new server
    bcastserver.start() # starts accepting bcast connections and returns
    tradeserver.serve_forever() # starts accepting trade connections and blocks until tradeserver stops
    bcastserver.stop() # stops also the bcast server

The gevent introduction documentation explains why this works:

Unlike other network libraries, though in a similar fashion as eventlet, gevent starts the event loop implicitly in a dedicated greenlet. There’s no reactor that you must call a run() or dispatch() function on. When a function from gevent’s API wants to block, it obtains the gevent.hub.Hub instance — a special greenlet that runs the event loop — and switches to it (it is said that the greenlet yielded control to the Hub).

When serve_forever() blocks, it does not prevent either server from continuing communication.

Note: In the above code the trader server is the one that decides when the whole application stops. If you want the broadcast server to decide this, you should swap them in the start() and serve_forever() calls.

Start each server loop in its own instance of Python (one console per gevent). I've never understood trying to run multiple servers from one program. You can run the same server many times and use a reverse proxy like nginx to load balance and route accordingly.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top