Pulled examples into docs proper, for better linkage on the Web.
This commit is contained in:
@@ -28,7 +28,7 @@ The canonical client-side example is a web crawler. This use case is given a li
|
|||||||
for body in pool.imap(fetch, urls):
|
for body in pool.imap(fetch, urls):
|
||||||
print "got body", len(body)
|
print "got body", len(body)
|
||||||
|
|
||||||
There is a slightly more complex version of this in the file ``examples/webcrawler.py`` in the source distribution. Here's a tour of the interesting lines in this crawler.
|
There is a slightly more complex version of this in the :ref:`web crawler example <web_crawler_example>`. Here's a tour of the interesting lines in this crawler.
|
||||||
|
|
||||||
``from eventlet.green import urllib2`` is how you import a cooperatively-yielding version of urllib2. It is the same in all respects to the standard version, except that it uses green sockets for its communication.
|
``from eventlet.green import urllib2`` is how you import a cooperatively-yielding version of urllib2. It is the same in all respects to the standard version, except that it uses green sockets for its communication.
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ Here's a simple server-side example, a simple echo server::
|
|||||||
new_sock, address = server.accept()
|
new_sock, address = server.accept()
|
||||||
pool.spawn_n(handle, new_sock)
|
pool.spawn_n(handle, new_sock)
|
||||||
|
|
||||||
The file ``examples/echoserver.py`` contains a somewhat more robust and complex version of this example.
|
The file :ref:`echo server example <echo_server_example>` contains a somewhat more robust and complex version of this example.
|
||||||
|
|
||||||
``from eventlet.green import socket`` imports eventlet's socket module, which is just like the regular socket module, but cooperatively yielding.
|
``from eventlet.green import socket`` imports eventlet's socket module, which is just like the regular socket module, but cooperatively yielding.
|
||||||
|
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
Chat Server Example
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
Let's look at a simple example, a chat server::
|
|
||||||
|
|
||||||
import eventlet
|
|
||||||
from eventlet.green import socket
|
|
||||||
|
|
||||||
participants = []
|
|
||||||
|
|
||||||
def read_chat_forever(writer, reader):
|
|
||||||
line = reader.readline()
|
|
||||||
while line:
|
|
||||||
print "Chat:", line.strip()
|
|
||||||
for p in participants:
|
|
||||||
if p is not writer: # Don't echo
|
|
||||||
p.write(line)
|
|
||||||
p.flush()
|
|
||||||
line = reader.readline()
|
|
||||||
participants.remove(writer)
|
|
||||||
print "Participant left chat."
|
|
||||||
|
|
||||||
try:
|
|
||||||
print "ChatServer starting up on port 3000"
|
|
||||||
server = socket.socket()
|
|
||||||
server.bind(('0.0.0.0', 3000))
|
|
||||||
server.listen(50)
|
|
||||||
while True:
|
|
||||||
new_connection, address = server.accept()
|
|
||||||
print "Participant joined chat."
|
|
||||||
new_writer = new_connection.makefile('w')
|
|
||||||
participants.append(new_writer)
|
|
||||||
eventlet.spawn_n(read_chat_forever,
|
|
||||||
new_writer,
|
|
||||||
new_connection.makefile('r'))
|
|
||||||
except (KeyboardInterrupt, SystemExit):
|
|
||||||
print "ChatServer exiting."
|
|
||||||
|
|
||||||
The server shown here is very easy to understand. If it was written using Python's threading module instead of eventlet, the control flow and code layout would be exactly the same. The call to :func:`~eventlet.spawn` would be replaced with the appropriate call to the :mod:`threading` module. Using Eventlet, this simple program can accommodate thousands and thousands of simultaneous users, consuming very little RAM and very little CPU.
|
|
||||||
|
|
||||||
What sort of servers would require concurrency like this? A typical Web server might measure traffic on the order of 10 requests per second; at any given moment, the server might only have a handful of HTTP connections open simultaneously. However, a chat server, instant messenger server, or multiplayer game server will need to maintain one connection per online user to be able to send messages to them as other users chat or make moves in the game. Also, as advanced Web development techniques such as Ajax, Ajax polling, and Comet (the "Long Poll") become more popular, Web servers will need to be able to deal with many more simultaneous requests. In fact, since the Comet technique involves the client making a new request as soon as the server closes an old one, a Web server servicing Comet clients has the same characteristics as a chat or game server: one connection per online user.
|
|
37
doc/examples.rst
Normal file
37
doc/examples.rst
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
Here are a bunch of small example programs that use Eventlet. All of these examples can be found in the ``examples`` directory of a source copy of Eventlet.
|
||||||
|
|
||||||
|
.. _web_crawler_example:
|
||||||
|
Web Crawler
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. literalinclude:: ../examples/webcrawler.py
|
||||||
|
|
||||||
|
.. _wsgi_server_example:
|
||||||
|
WSGI Server
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. literalinclude:: ../examples/wsgi.py
|
||||||
|
|
||||||
|
.. _echo_server_example:
|
||||||
|
Echo Server
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. literalinclude:: ../examples/echoserver.py
|
||||||
|
|
||||||
|
.. _socket_connect_example:
|
||||||
|
Socket Connect
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. literalinclude:: ../examples/connect.py
|
||||||
|
|
||||||
|
.. _chat_server_example:
|
||||||
|
Multi-User Chat Server
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
This is a little different from the echo server, in that it broadcasts the
|
||||||
|
messages to all participants, not just the sender.
|
||||||
|
|
||||||
|
.. literalinclude:: ../examples/chat_server.py
|
@@ -32,7 +32,7 @@ Contents
|
|||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
basic_usage
|
basic_usage
|
||||||
chat_server_example
|
examples
|
||||||
ssl
|
ssl
|
||||||
threading
|
threading
|
||||||
hubs
|
hubs
|
||||||
|
@@ -1,51 +0,0 @@
|
|||||||
"""This is a simple echo server that demonstrates an accept loop. To use it,
|
|
||||||
run this script and then run 'telnet localhost 6011' in a different terminal.
|
|
||||||
|
|
||||||
If you send an empty line to the echo server it will close the connection while
|
|
||||||
leaving the server running. If you send the word "shutdown" to the echo server
|
|
||||||
it will gracefully exit, terminating any other open connections.
|
|
||||||
|
|
||||||
The actual accept loop logic is fully contained within the run_accept_loop
|
|
||||||
function. Everything else is setup.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from eventlet.green import socket
|
|
||||||
from eventlet.api import spawn
|
|
||||||
|
|
||||||
class Acceptor(object):
|
|
||||||
def __init__(self, port=6011):
|
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.sock.setsockopt(
|
|
||||||
socket.SOL_SOCKET,
|
|
||||||
socket.SO_REUSEADDR, 1)
|
|
||||||
self.sock.bind(('localhost', port))
|
|
||||||
self.sock.listen(50)
|
|
||||||
self.sock.settimeout(0.5)
|
|
||||||
self.done = False
|
|
||||||
|
|
||||||
def run_accept_loop(self):
|
|
||||||
while not self.done:
|
|
||||||
try:
|
|
||||||
spawn(self.handle_one_client, self.sock.accept())
|
|
||||||
except socket.timeout:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def handle_one_client(self, sockpair):
|
|
||||||
sock, addr = sockpair
|
|
||||||
print "Accepted client", addr
|
|
||||||
fd = sock.makefile()
|
|
||||||
line = fd.readline()
|
|
||||||
while line.strip():
|
|
||||||
fd.write(line)
|
|
||||||
fd.flush()
|
|
||||||
if line.startswith("shutdown"):
|
|
||||||
self.done = True
|
|
||||||
print "Received shutdown"
|
|
||||||
break
|
|
||||||
line = fd.readline()
|
|
||||||
print "Done with client", addr
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
a = Acceptor()
|
|
||||||
a.run_accept_loop()
|
|
||||||
print "Exiting"
|
|
32
examples/chat_server.py
Normal file
32
examples/chat_server.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import eventlet
|
||||||
|
from eventlet.green import socket
|
||||||
|
|
||||||
|
participants = []
|
||||||
|
|
||||||
|
def read_chat_forever(writer, reader):
|
||||||
|
line = reader.readline()
|
||||||
|
while line:
|
||||||
|
print "Chat:", line.strip()
|
||||||
|
for p in participants:
|
||||||
|
if p is not writer: # Don't echo
|
||||||
|
p.write(line)
|
||||||
|
p.flush()
|
||||||
|
line = reader.readline()
|
||||||
|
participants.remove(writer)
|
||||||
|
print "Participant left chat."
|
||||||
|
|
||||||
|
try:
|
||||||
|
print "ChatServer starting up on port 3000"
|
||||||
|
server = socket.socket()
|
||||||
|
server.bind(('0.0.0.0', 3000))
|
||||||
|
server.listen(50)
|
||||||
|
while True:
|
||||||
|
new_connection, address = server.accept()
|
||||||
|
print "Participant joined chat."
|
||||||
|
new_writer = new_connection.makefile('w')
|
||||||
|
participants.append(new_writer)
|
||||||
|
eventlet.spawn_n(read_chat_forever,
|
||||||
|
new_writer,
|
||||||
|
new_connection.makefile('r'))
|
||||||
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
print "ChatServer exiting."
|
Reference in New Issue
Block a user