Deprecated tcp_server, added an accept loop example, fixed up two sites that still used tcp_server.

This commit is contained in:
Ryan Williams
2009-11-24 17:17:57 -05:00
parent 48394ec5b7
commit 0b9db4a713
5 changed files with 89 additions and 31 deletions

View File

@@ -8,6 +8,8 @@ import threading
from eventlet.support import greenlets as greenlet
import warnings
__all__ = [
'call_after', 'exc_after', 'getcurrent', 'get_default_hub', 'get_hub',
'GreenletExit', 'kill', 'sleep', 'spawn', 'spew', 'switch',
@@ -33,10 +35,6 @@ def tcp_listener(address, backlog=50):
Listen on the given ``(ip, port)`` *address* with a TCP socket. Returns a
socket object on which one should call ``accept()`` to accept a connection
on the newly bound socket.
Generally, the returned socket will be passed to :func:`tcp_server`, which
accepts connections forever and spawns greenlets for each incoming
connection.
"""
from eventlet import greenio, util
socket = greenio.GreenSocket(util.tcp_socket())
@@ -52,10 +50,6 @@ def ssl_listener(address, certificate, private_key):
Returns a socket object on which one should call ``accept()`` to
accept a connection on the newly bound socket.
Generally, the returned socket will be passed to
:func:`~eventlet.api.tcp_server`, which accepts connections forever and
spawns greenlets for each incoming connection.
"""
from eventlet import util
socket = util.wrap_ssl(util.tcp_socket(), certificate, private_key, True)
@@ -76,6 +70,14 @@ def connect_tcp(address, localaddr=None):
def tcp_server(listensocket, server, *args, **kw):
"""
**Deprecated** Please write your own accept loop instead, like this::
while True:
api.spawn(server, listensocket.accept(), <other_args>)
A more complex accept loop can be found in ``examples/accept_loop.py``.
*Original documentation:*
Given a socket, accept connections forever, spawning greenlets and
executing *server* for each new incoming connection. When *server* returns
False, the :func:`tcp_server()` greenlet will end.
@@ -85,6 +87,9 @@ def tcp_server(listensocket, server, *args, **kw):
:param \*args: The positional arguments to pass to *server*.
:param \*\*kw: The keyword arguments to pass to *server*.
"""
warnings.warn("tcp_server is deprecated, please write your own "\
"accept loop instead (see examples/accept_loop.py)",
DeprecationWarning, stacklevel=2)
working = [True]
try:
while working[0] is not False:

View File

@@ -1,5 +1,6 @@
import socket
import sys
import errno
from code import InteractiveConsole
from eventlet import api
@@ -68,33 +69,27 @@ class SocketConsole(greenlets.greenlet):
def backdoor_server(server, locals=None):
print "backdoor listening on %s:%s" % server.getsockname()
""" Runs a backdoor server on the socket, accepting connections and
running backdoor consoles for each client that connects.
"""
print "backdoor server listening on %s:%s" % server.getsockname()
try:
try:
while True:
(conn, (host, port)) = server.accept()
print "backdoor connected to %s:%s" % (host, port)
fl = conn.makeGreenFile("rw")
fl.newlines = '\n'
greenlet = SocketConsole(fl, (host, port), locals)
hub = api.get_hub()
hub.schedule_call_global(0, greenlet.switch)
socketpair = server.accept()
backdoor(socketpair, locals)
except socket.error, e:
# Broken pipe means it was shutdown
if e[0] != 32:
if e[0] != errno.EPIPE:
raise
finally:
server.close()
def backdoor((conn, addr), locals=None):
"""
Use this with tcp_server like so::
api.tcp_server(
api.tcp_listener(('127.0.0.1', 9000)),
backdoor.backdoor,
{})
"""Sets up an interactive console on a socket with a connected client.
This does not block the caller, as it spawns a new greenlet to handle
the console.
"""
host, port = addr
print "backdoor to %s:%s" % (host, port)
@@ -106,7 +101,5 @@ def backdoor((conn, addr), locals=None):
if __name__ == '__main__':
api.tcp_server(api.tcp_listener(('127.0.0.1', 9000)),
backdoor,
{})
backdoor_server(api.tcp_listener(('127.0.0.1', 9000)), {})

View File

@@ -130,12 +130,14 @@ class GreenSSLObject(object):
try:
# >= Python 2.6
from eventlet.green import ssl
def ssl(sock, certificate=None, private_key=None):
warnings.warn("socket.ssl() is deprecated. Use ssl.wrap_socket() instead.",
DeprecationWarning, stacklevel=2)
return ssl.sslwrap_simple(sock, keyfile, certfile)
except ImportError:
# <= Python 2.5 compatibility
def ssl(sock, certificate=None, private_key=None):
from eventlet import util
wrapped = util.wrap_ssl(sock, certificate, private_key)

51
examples/accept_loop.py Normal file
View File

@@ -0,0 +1,51 @@
"""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"

View File

@@ -91,7 +91,12 @@ class TestApi(TestCase):
check_hub()
def test_server(self):
def test_tcp_server(self):
import warnings
# disabling tcp_server warnings because we're testing tcp_server here
warnings.filterwarnings(action = 'ignore',
message='.*tcp_server.*',
category=DeprecationWarning)
connected = []
server = api.tcp_listener(('0.0.0.0', 0))
bound_port = server.getsockname()[1]
@@ -134,8 +139,10 @@ class TestApi(TestCase):
bound_port = server.getsockname()[1]
done = [False]
def client_connected((conn, addr)):
conn.close()
def client_closer(sock):
while True:
(conn, addr) = sock.accept()
conn.close()
def go():
client = util.tcp_socket()
@@ -153,7 +160,7 @@ class TestApi(TestCase):
api.call_after(0, go)
server_coro = api.spawn(api.tcp_server, server, client_connected)
server_coro = api.spawn(client_closer, server)
while not done[0]:
api.sleep(0)
api.kill(server_coro)