From 5121a9ba4acf890955d407275a3e5f1955c8b283 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 11 Oct 2014 15:52:14 +0200 Subject: [PATCH 1/3] asyncio doc: the "Get HTTP headers" example now supports HTTPS --- Doc/library/asyncio-stream.rst | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index a4a997e6098..19ec935a104 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -238,8 +238,11 @@ IncompleteReadError Read bytes string before the end of stream was reached (:class:`bytes`). -Example -======= +Stream examples +=============== + +Get HTTP headers +---------------- Simple example querying HTTP headers of the URL passed on the command line:: @@ -250,10 +253,14 @@ Simple example querying HTTP headers of the URL passed on the command line:: @asyncio.coroutine def print_http_headers(url): url = urllib.parse.urlsplit(url) - reader, writer = yield from asyncio.open_connection(url.hostname, 80) - query = ('HEAD {url.path} HTTP/1.0\r\n' - 'Host: {url.hostname}\r\n' - '\r\n').format(url=url) + if url.scheme == 'https': + connect = asyncio.open_connection(url.hostname, 443, ssl=True) + else: + connect = asyncio.open_connection(url.hostname, 80) + reader, writer = yield from connect + query = ('HEAD {path} HTTP/1.0\r\n' + 'Host: {hostname}\r\n' + '\r\n').format(path=url.path or '/', hostname=url.hostname) writer.write(query.encode('latin-1')) while True: line = yield from reader.readline() @@ -263,6 +270,9 @@ Simple example querying HTTP headers of the URL passed on the command line:: if line: print('HTTP header> %s' % line) + # Ignore the body, close the socket + writer.close() + url = sys.argv[1] loop = asyncio.get_event_loop() task = asyncio.async(print_http_headers(url)) From 6888b96cee44364f5414b0e4dbfc69dba8b639b4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 11 Oct 2014 16:15:58 +0200 Subject: [PATCH 2/3] asyncio doc: cleanup Hello World examples --- Doc/library/asyncio-eventloop.rst | 12 ++++++++---- Doc/library/asyncio-task.rst | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 8706b41ff47..ed385120805 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -633,13 +633,16 @@ Handle Cancel the call. +Event loop examples +=================== .. _asyncio-hello-world-callback: -Example: Hello World (callback) -------------------------------- +Hello World with a callback +--------------------------- -Print ``Hello World`` every two seconds, using a callback:: +Print ``"Hello World"`` every two seconds using a callback scheduled by the +:meth:`BaseEventLoop.call_soon` method:: import asyncio @@ -656,7 +659,8 @@ Print ``Hello World`` every two seconds, using a callback:: .. seealso:: - :ref:`Hello World example using a coroutine `. + The :ref:`Hello World coroutine ` example + uses a :ref:`coroutine `. Example: Set signal handlers for SIGINT and SIGTERM diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index e7c316df9e9..8c4d790eace 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -98,8 +98,9 @@ Print ``"Hello World"`` every two seconds using a coroutine:: .. seealso:: - :ref:`Hello World example using a callback `. - + The :ref:`Hello World with a callback ` + example uses a callback scheduled by the :meth:`BaseEventLoop.call_soon` + method. Example: Chain coroutines ^^^^^^^^^^^^^^^^^^^^^^^^^ From 04e6df330ddbec28cbbcba0f36235040e267692d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 11 Oct 2014 16:16:27 +0200 Subject: [PATCH 3/3] asyncio doc: add examples showing the 3 ways to wait for data from an open socket --- Doc/library/asyncio-eventloop.rst | 60 +++++++++++++++++++++++++-- Doc/library/asyncio-protocol.rst | 68 ++++++++++++++++++++++++++++--- Doc/library/asyncio-stream.rst | 50 +++++++++++++++++++++++ 3 files changed, 168 insertions(+), 10 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index ed385120805..59682d3f908 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -339,6 +339,10 @@ On Windows with :class:`ProactorEventLoop`, these methods are not supported. Stop watching the file descriptor for write availability. +The :ref:`watch a file descriptor for read events ` +example uses the low-level :meth:`BaseEventLoop.add_reader` method to register +the file descriptor of a socket. + Low-level socket operations --------------------------- @@ -663,10 +667,59 @@ Print ``"Hello World"`` every two seconds using a callback scheduled by the uses a :ref:`coroutine `. -Example: Set signal handlers for SIGINT and SIGTERM ---------------------------------------------------- +.. _asyncio-watch-read-event: -Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM`:: +Watch a file descriptor for read events +--------------------------------------- + +Wait until a file descriptor received some data using the +:meth:`BaseEventLoop.add_reader` method and then close the event loop:: + + import asyncio + import socket + + # Create a pair of connected file descriptors + rsock, wsock = socket.socketpair() + loop = asyncio.get_event_loop() + + def reader(): + data = rsock.recv(100) + print("Received:", data.decode()) + # We are done: unregister the register + loop.remove_reader(rsock) + # Stop the event loop + loop.stop() + + # Wait for read event + loop.add_reader(rsock, reader) + + # Simulate the reception of data from the network + loop.call_soon(wsock.send, 'abc'.encode()) + + # Run the event loop + loop.run_forever() + + # We are done, close sockets and the event loop + rsock.close() + wsock.close() + loop.close() + +.. seealso:: + + The :ref:`register an open socket to wait for data using a protocol + ` example uses a low-level protocol created by the + :meth:`BaseEventLoop.create_connection` method. + + The :ref:`register an open socket to wait for data using streams + ` example uses high-level streams + created by the :func:`open_connection` function in a coroutine. + + +Set signal handlers for SIGINT and SIGTERM +------------------------------------------ + +Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM` using +the :meth:`BaseEventLoop.add_signal_handler` method:: import asyncio import functools @@ -688,4 +741,3 @@ Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM`:: loop.run_forever() finally: loop.close() - diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 92b055a7b56..3fa2f3ec50c 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -436,11 +436,11 @@ coroutine with ``yield from``. For example, the :meth:`StreamWriter.drain` coroutine can be used to wait until the write buffer is flushed. -Protocol example: TCP echo server and client -============================================ +Protocol examples +================= -Echo client ------------ +TCP echo client +--------------- TCP echo client example, send data and wait until the connection is closed:: @@ -473,8 +473,8 @@ having to write a short coroutine to handle the exception and stop the running loop. At :meth:`~BaseEventLoop.run_until_complete` exit, the loop is no longer running, so there is no need to stop the loop in case of an error. -Echo server ------------ +TCP echo server +--------------- TCP echo server example, send back received data and close the connection:: @@ -511,4 +511,60 @@ TCP echo server example, send back received data and close the connection:: methods are asynchronous. ``yield from`` is not needed because these transport methods are not coroutines. +.. _asyncio-register-socket: +Register an open socket to wait for data using a protocol +--------------------------------------------------------- + +Wait until a socket receives data using the +:meth:`BaseEventLoop.create_connection` method with a protocol, and then close +the event loop :: + + import asyncio + import socket + + # Create a pair of connected sockets + rsock, wsock = socket.socketpair() + loop = asyncio.get_event_loop() + + class MyProtocol(asyncio.Protocol): + transport = None + + def connection_made(self, transport): + self.transport = transport + + def data_received(self, data): + print("Received:", data.decode()) + + # We are done: close the transport (it will call connection_lost()) + self.transport.close() + + def connection_lost(self, exc): + # The socket has been closed, stop the event loop + loop.stop() + + # Register the socket to wait for data + connect_coro = loop.create_connection(MyProtocol, sock=rsock) + transport, protocol = loop.run_until_complete(connect_coro) + + # Simulate the reception of data from the network + loop.call_soon(wsock.send, 'abc'.encode()) + + # Run the event loop + loop.run_forever() + + # We are done, close sockets and the event loop + rsock.close() + wsock.close() + loop.close() + +.. seealso:: + + The :ref:`watch a file descriptor for read events + ` example uses the low-level + :meth:`BaseEventLoop.add_reader` method to register the file descriptor of a + socket. + + The :ref:`register an open socket to wait for data using streams + ` example uses high-level streams + created by the :func:`open_connection` function in a coroutine. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 19ec935a104..9db238013e4 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -283,3 +283,53 @@ Usage:: python example.py http://example.com/path/page.html +or with HTTPS:: + + python example.py https://example.com/path/page.html + +.. _asyncio-register-socket-streams: + +Register an open socket to wait for data using streams +------------------------------------------------------ + +Coroutine waiting until a socket receives data using the +:func:`open_connection` function:: + + import asyncio + import socket + + def wait_for_data(loop): + # Create a pair of connected sockets + rsock, wsock = socket.socketpair() + + # Register the open socket to wait for data + reader, writer = yield from asyncio.open_connection(sock=rsock, loop=loop) + + # Simulate the reception of data from the network + loop.call_soon(wsock.send, 'abc'.encode()) + + # Wait for data + data = yield from reader.read(100) + + # Got data, we are done: close the socket + print("Received:", data.decode()) + writer.close() + + # Close the second socket + wsock.close() + + loop = asyncio.get_event_loop() + loop.run_until_complete(wait_for_data(loop)) + loop.close() + +.. seealso:: + + The :ref:`register an open socket to wait for data using a protocol + ` example uses a low-level protocol created by the + :meth:`BaseEventLoop.create_connection` method. + + The :ref:`watch a file descriptor for read events + ` example uses the low-level + :meth:`BaseEventLoop.add_reader` method to register the file descriptor of a + socket. +