Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gevent StreamServer.start() does not seem to do what I expect

I'm trying to wrap my brain around the concepts that gevent employs. Here's an example from the gevent code repository. It's a simple echo server.

from gevent.server import StreamServer

# this handler will be run for each incoming connection in a dedicated greenlet
def echo(socket, address):
    print ('New connection from %s:%s' % address)
    socket.sendall('Welcome to the echo server! Type quit to exit.\r\n')
    # using a makefile because we want to use readline()
    fileobj = socket.makefile()
    while True:
        line = fileobj.readline()
        if not line:
            print ("client disconnected")
            break
        if line.strip().lower() == 'quit':
            print ("client quit")
            break
        fileobj.write(line)
        fileobj.flush()
        print ("echoed %r" % line)


if __name__ == '__main__':
    # to make the server use SSL, pass certfile and keyfile arguments to the constructor
    server = StreamServer(('0.0.0.0', 6000), echo)
    # to start the server asynchronously, use its start() method;
    # we use blocking serve_forever() here because we have no other jobs
    print ('Starting echo server on port 6000')
    server.serve_forever()

That seems quite straightforward and I it works. However as it says in the comment that serve_forever() is a blocking function. If I change the last line to server.start() the program will stop after executing each line once. I am doing something wrong but the documentation is not very helpful.

In the documentation section implementing servers with gevent, it says that using start() should spawn a new greenlet for each new connection when using the following code:

 def handle(socket, address):
     print 'new connection!'

 server = StreamServer(('127.0.0.1', 1234), handle) # creates a new server
 server.start() # start accepting new connections

And then right after it says that The server_forever() method calls start() and then waits until interrupted or until the server is stopped. How am I supposed to run the server using start() so that it actually remains alive to catch the first connection?

Also:

  1. What is the difference between start() and serve_forever()?
  2. In what contexts should I choose one over the other?
  3. Are calls to gevent.spawn() and gevent.joinall() necessary when using the first method, but somehow so obvious that they've been left out of the StreamServer-documentation?
like image 511
msvalkon Avatar asked Apr 23 '12 20:04

msvalkon


1 Answers

  1. start() is an asynchronous function that puts a server in a listening mode. It does not prevent your program from exiting though, which is your responsibility.
  2. in simple cases you can use serve_forever(). start() becomes useful when you need to start multiple servers or do something else in addition to starting a server.
  3. no, gevent.spawn() and gevent.joinall() have nothing to do with servers.

With gevent 1.0 it's actually best to use gevent.wait() which blocks until there are no more active connections/greenlets/listeners/watchers.

Here's an example: https://github.com/gevent/gevent/blob/master/examples/portforwarder.py

like image 106
Denis Avatar answered Sep 18 '22 21:09

Denis