Deprecated tcp_server, added an accept loop example, fixed up two sites that still used tcp_server.
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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)), {})
|
||||
|
||||
|
||||
@@ -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
51
examples/accept_loop.py
Normal 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"
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user