2014-01-23 10:05:01 +00:00
|
|
|
.. currentmodule:: asyncio
|
|
|
|
|
2014-02-02 14:03:02 +00:00
|
|
|
.. _asyncio-streams:
|
2014-01-24 16:33:20 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
=======
|
|
|
|
Streams
|
|
|
|
=======
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Streams are high-level async/await-ready primitives to work with
|
|
|
|
network connections. Streams allow send and receive data without
|
|
|
|
using callbacks or low-level protocols and transports.
|
2017-07-25 23:03:51 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Here's an example of a TCP echo client written using asyncio
|
|
|
|
streams::
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
import asyncio
|
|
|
|
|
|
|
|
async def tcp_echo_client(message):
|
|
|
|
reader, writer = await asyncio.open_connection(
|
|
|
|
'127.0.0.1', 8888)
|
|
|
|
|
|
|
|
print(f'Send: {message!r}')
|
|
|
|
writer.write(message.encode())
|
|
|
|
|
|
|
|
data = await reader.read(100)
|
|
|
|
print(f'Received: {data.decode()!r}')
|
|
|
|
|
|
|
|
print('Close the connection')
|
|
|
|
writer.close()
|
2015-10-19 20:18:04 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
asyncio.run(tcp_echo_client('Hello World!'))
|
2015-10-19 20:18:04 +00:00
|
|
|
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
.. rubric:: Stream Functions
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
The following top-level asyncio functions can be used to create
|
|
|
|
and work with streams:
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
.. coroutinefunction:: open_connection(host=None, port=None, \*, \
|
|
|
|
loop=None, limit=None, ssl=None, family=0, \
|
|
|
|
proto=0, flags=0, sock=None, local_addr=None, \
|
|
|
|
server_hostname=None, ssl_handshake_timeout=None)
|
|
|
|
|
|
|
|
Establish a network connection and return a pair of
|
|
|
|
``(reader, writer)``.
|
|
|
|
|
|
|
|
The returned *reader* and *writer* objects are instances of
|
|
|
|
:class:`StreamReader` and :class:`StreamWriter` classes.
|
|
|
|
|
|
|
|
The *loop* argument is optional and can always be determined
|
|
|
|
automatically when this method is awaited from a coroutine.
|
|
|
|
|
|
|
|
*limit* determines the buffer size limit used by the
|
2018-06-08 15:36:00 +00:00
|
|
|
returned :class:`StreamReader` instance.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-06-08 15:36:00 +00:00
|
|
|
The rest of the arguments are passed directly to
|
2018-09-11 16:54:40 +00:00
|
|
|
:meth:`loop.create_connection`.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-06-08 15:36:00 +00:00
|
|
|
.. versionadded:: 3.7
|
|
|
|
|
|
|
|
The *ssl_handshake_timeout* parameter.
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
.. coroutinefunction:: start_server(client_connected_cb, host=None, \
|
|
|
|
port=None, \*, loop=None, limit=None, \
|
|
|
|
family=socket.AF_UNSPEC, \
|
|
|
|
flags=socket.AI_PASSIVE, sock=None, \
|
|
|
|
backlog=100, ssl=None, reuse_address=None, \
|
|
|
|
reuse_port=None, ssl_handshake_timeout=None, \
|
|
|
|
start_serving=True)
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Start a socket server.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-06-08 15:36:00 +00:00
|
|
|
The *client_connected_cb* callback is called whenever a new client
|
2018-09-11 16:54:40 +00:00
|
|
|
connection is established. It receives a ``(reader, writer)`` pair
|
|
|
|
as two arguments, instances of the :class:`StreamReader` and
|
|
|
|
:class:`StreamWriter` classes.
|
2018-06-08 15:36:00 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
*client_connected_cb* can be a plain callable or a
|
2018-06-08 15:36:00 +00:00
|
|
|
:ref:`coroutine function <coroutine>`; if it is a coroutine function,
|
2018-09-11 16:54:40 +00:00
|
|
|
it will be automatically wrapped into a :class:`Task`.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
The *loop* argument is optional and can always be determined
|
|
|
|
automatically when this method is awaited from a coroutine.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
*limit* determines the buffer size limit used by the
|
|
|
|
returned :class:`StreamReader` instance.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
The rest of the arguments are passed directly to
|
|
|
|
:meth:`loop.create_server`.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-06-08 15:36:00 +00:00
|
|
|
.. versionadded:: 3.7
|
|
|
|
|
|
|
|
The *ssl_handshake_timeout* and *start_serving* parameters.
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
.. coroutinefunction:: open_unix_connection(path=None, \*, loop=None, \
|
|
|
|
limit=None, ssl=None, sock=None, \
|
|
|
|
server_hostname=None, ssl_handshake_timeout=None)
|
2014-02-20 19:10:02 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Establish a UNIX socket connection and return a pair of
|
|
|
|
``(reader, writer)``.
|
2018-06-08 15:36:00 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Similar to :func:`open_connection` but operates on UNIX sockets.
|
2014-02-20 19:10:02 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
See also the documentation of :meth:`loop.create_unix_connection`.
|
2014-02-20 19:10:02 +00:00
|
|
|
|
|
|
|
Availability: UNIX.
|
|
|
|
|
2018-06-08 15:36:00 +00:00
|
|
|
.. versionadded:: 3.7
|
|
|
|
|
|
|
|
The *ssl_handshake_timeout* parameter.
|
|
|
|
|
|
|
|
.. versionchanged:: 3.7
|
|
|
|
|
|
|
|
The *path* parameter can now be a :term:`path-like object`
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
.. coroutinefunction:: start_unix_server(client_connected_cb, path=None, \
|
|
|
|
\*, loop=None, limit=None, sock=None, \
|
|
|
|
backlog=100, ssl=None, ssl_handshake_timeout=None, \
|
|
|
|
start_serving=True)
|
2018-06-08 15:36:00 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Start a UNIX socket server.
|
2018-06-08 15:36:00 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Similar to :func:`start_server` but operates on UNIX sockets.
|
2014-02-20 19:10:02 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
See also the documentation of :meth:`loop.create_unix_server`.
|
2014-02-20 19:10:02 +00:00
|
|
|
|
|
|
|
Availability: UNIX.
|
|
|
|
|
2018-06-08 15:36:00 +00:00
|
|
|
.. versionadded:: 3.7
|
|
|
|
|
|
|
|
The *ssl_handshake_timeout* and *start_serving* parameters.
|
|
|
|
|
|
|
|
.. versionchanged:: 3.7
|
|
|
|
|
|
|
|
The *path* parameter can now be a :term:`path-like object`.
|
|
|
|
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
.. rubric:: Contents
|
|
|
|
|
|
|
|
* `StreamReader`_ and `StreamWriter`_
|
|
|
|
* `StreamReaderProtocol`_
|
|
|
|
* `Examples`_
|
|
|
|
|
|
|
|
|
2014-01-23 10:05:01 +00:00
|
|
|
StreamReader
|
|
|
|
============
|
|
|
|
|
2018-09-11 18:45:26 +00:00
|
|
|
.. class:: StreamReader(limit=_DEFAULT_LIMIT, loop=None)
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2015-02-25 13:24:15 +00:00
|
|
|
This class is :ref:`not thread safe <asyncio-multithreading>`.
|
|
|
|
|
2018-09-11 18:45:26 +00:00
|
|
|
The *limit* argument's default value is set to _DEFAULT_LIMIT which is 2**16 (64 KiB)
|
|
|
|
|
2014-01-23 10:05:01 +00:00
|
|
|
.. method:: exception()
|
|
|
|
|
|
|
|
Get the exception.
|
|
|
|
|
|
|
|
.. method:: feed_eof()
|
|
|
|
|
2014-02-20 19:10:02 +00:00
|
|
|
Acknowledge the EOF.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
.. method:: feed_data(data)
|
|
|
|
|
2014-02-20 19:10:02 +00:00
|
|
|
Feed *data* bytes in the internal buffer. Any operations waiting
|
|
|
|
for the data will be resumed.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
.. method:: set_exception(exc)
|
|
|
|
|
|
|
|
Set the exception.
|
|
|
|
|
|
|
|
.. method:: set_transport(transport)
|
|
|
|
|
|
|
|
Set the transport.
|
|
|
|
|
2015-02-12 21:49:18 +00:00
|
|
|
.. coroutinemethod:: read(n=-1)
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2014-02-20 19:10:02 +00:00
|
|
|
Read up to *n* bytes. If *n* is not provided, or set to ``-1``,
|
|
|
|
read until EOF and return all read bytes.
|
|
|
|
|
|
|
|
If the EOF was received and the internal buffer is empty,
|
|
|
|
return an empty ``bytes`` object.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2015-02-12 21:49:18 +00:00
|
|
|
.. coroutinemethod:: readline()
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2014-02-20 19:10:02 +00:00
|
|
|
Read one line, where "line" is a sequence of bytes ending with ``\n``.
|
|
|
|
|
|
|
|
If EOF is received, and ``\n`` was not found, the method will
|
|
|
|
return the partial read bytes.
|
|
|
|
|
|
|
|
If the EOF was received and the internal buffer is empty,
|
|
|
|
return an empty ``bytes`` object.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2015-02-12 21:49:18 +00:00
|
|
|
.. coroutinemethod:: readexactly(n)
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2014-01-27 10:58:49 +00:00
|
|
|
Read exactly *n* bytes. Raise an :exc:`IncompleteReadError` if the end of
|
|
|
|
the stream is reached before *n* can be read, the
|
|
|
|
:attr:`IncompleteReadError.partial` attribute of the exception contains
|
|
|
|
the partial read bytes.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2016-10-17 21:34:46 +00:00
|
|
|
.. coroutinemethod:: readuntil(separator=b'\\n')
|
2016-05-16 20:23:00 +00:00
|
|
|
|
|
|
|
Read data from the stream until ``separator`` is found.
|
|
|
|
|
|
|
|
On success, the data and separator will be removed from the
|
|
|
|
internal buffer (consumed). Returned data will include the
|
|
|
|
separator at the end.
|
|
|
|
|
|
|
|
Configured stream limit is used to check result. Limit sets the
|
|
|
|
maximal length of data that can be returned, not counting the
|
|
|
|
separator.
|
|
|
|
|
|
|
|
If an EOF occurs and the complete separator is still not found,
|
|
|
|
an :exc:`IncompleteReadError` exception will be
|
|
|
|
raised, and the internal buffer will be reset. The
|
|
|
|
:attr:`IncompleteReadError.partial` attribute may contain the
|
|
|
|
separator partially.
|
|
|
|
|
|
|
|
If the data cannot be read because of over limit, a
|
|
|
|
:exc:`LimitOverrunError` exception will be raised, and the data
|
|
|
|
will be left in the internal buffer, so it can be read again.
|
|
|
|
|
|
|
|
.. versionadded:: 3.5.2
|
|
|
|
|
2014-02-20 19:10:02 +00:00
|
|
|
.. method:: at_eof()
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Return ``True`` if the buffer is empty and :meth:`feed_eof`
|
|
|
|
was called.
|
2014-02-20 19:10:02 +00:00
|
|
|
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
StreamWriter
|
|
|
|
============
|
|
|
|
|
|
|
|
.. class:: StreamWriter(transport, protocol, reader, loop)
|
|
|
|
|
|
|
|
Wraps a Transport.
|
|
|
|
|
|
|
|
This exposes :meth:`write`, :meth:`writelines`, :meth:`can_write_eof()`,
|
|
|
|
:meth:`write_eof`, :meth:`get_extra_info` and :meth:`close`. It adds
|
|
|
|
:meth:`drain` which returns an optional :class:`Future` on which you can
|
|
|
|
wait for flow control. It also adds a transport attribute which references
|
|
|
|
the :class:`Transport` directly.
|
|
|
|
|
2015-02-25 13:24:15 +00:00
|
|
|
This class is :ref:`not thread safe <asyncio-multithreading>`.
|
|
|
|
|
2014-01-23 10:05:01 +00:00
|
|
|
.. attribute:: transport
|
|
|
|
|
|
|
|
Transport.
|
|
|
|
|
2014-02-08 21:50:07 +00:00
|
|
|
.. method:: can_write_eof()
|
|
|
|
|
|
|
|
Return :const:`True` if the transport supports :meth:`write_eof`,
|
|
|
|
:const:`False` if not. See :meth:`WriteTransport.can_write_eof`.
|
|
|
|
|
2014-01-23 10:05:01 +00:00
|
|
|
.. method:: close()
|
|
|
|
|
|
|
|
Close the transport: see :meth:`BaseTransport.close`.
|
|
|
|
|
2018-01-24 22:30:30 +00:00
|
|
|
.. method:: is_closing()
|
|
|
|
|
|
|
|
Return ``True`` if the writer is closing or is closed.
|
|
|
|
|
|
|
|
.. versionadded:: 3.7
|
|
|
|
|
|
|
|
.. coroutinemethod:: wait_closed()
|
|
|
|
|
|
|
|
Wait until the writer is closed.
|
|
|
|
|
|
|
|
Should be called after :meth:`close` to wait until the underlying
|
|
|
|
connection (and the associated transport/protocol pair) is closed.
|
|
|
|
|
|
|
|
.. versionadded:: 3.7
|
|
|
|
|
2015-02-12 21:49:18 +00:00
|
|
|
.. coroutinemethod:: drain()
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2014-11-28 16:45:41 +00:00
|
|
|
Let the write buffer of the underlying transport a chance to be flushed.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2014-08-25 15:04:12 +00:00
|
|
|
The intended use is to write::
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
w.write(data)
|
2017-12-11 15:35:49 +00:00
|
|
|
await w.drain()
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2014-11-28 16:45:41 +00:00
|
|
|
When the size of the transport buffer reaches the high-water limit (the
|
|
|
|
protocol is paused), block until the size of the buffer is drained down
|
|
|
|
to the low-water limit and the protocol is resumed. When there is nothing
|
|
|
|
to wait for, the yield-from continues immediately.
|
|
|
|
|
|
|
|
Yielding from :meth:`drain` gives the opportunity for the loop to
|
|
|
|
schedule the write operation and flush the buffer. It should especially
|
|
|
|
be used when a possibly large amount of data is written to the transport,
|
|
|
|
and the coroutine does not yield-from between calls to :meth:`write`.
|
2014-08-25 15:04:12 +00:00
|
|
|
|
|
|
|
This method is a :ref:`coroutine <coroutine>`.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
.. method:: get_extra_info(name, default=None)
|
|
|
|
|
|
|
|
Return optional transport information: see
|
|
|
|
:meth:`BaseTransport.get_extra_info`.
|
|
|
|
|
|
|
|
.. method:: write(data)
|
|
|
|
|
|
|
|
Write some *data* bytes to the transport: see
|
|
|
|
:meth:`WriteTransport.write`.
|
|
|
|
|
|
|
|
.. method:: writelines(data)
|
|
|
|
|
|
|
|
Write a list (or any iterable) of data bytes to the transport:
|
|
|
|
see :meth:`WriteTransport.writelines`.
|
|
|
|
|
|
|
|
.. method:: write_eof()
|
|
|
|
|
|
|
|
Close the write end of the transport after flushing buffered data:
|
|
|
|
see :meth:`WriteTransport.write_eof`.
|
|
|
|
|
|
|
|
|
|
|
|
StreamReaderProtocol
|
|
|
|
====================
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
.. class:: StreamReaderProtocol(stream_reader, client_connected_cb=None, \
|
|
|
|
loop=None)
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
Trivial helper class to adapt between :class:`Protocol` and
|
2016-04-19 19:50:19 +00:00
|
|
|
:class:`StreamReader`. Subclass of :class:`Protocol`.
|
2014-01-23 10:05:01 +00:00
|
|
|
|
|
|
|
*stream_reader* is a :class:`StreamReader` instance, *client_connected_cb*
|
|
|
|
is an optional function called with (stream_reader, stream_writer) when a
|
|
|
|
connection is made, *loop* is the event loop instance to use.
|
|
|
|
|
|
|
|
(This is a helper class instead of making :class:`StreamReader` itself a
|
|
|
|
:class:`Protocol` subclass, because the :class:`StreamReader` has other
|
2015-09-27 16:36:19 +00:00
|
|
|
potential uses, and to prevent the user of the :class:`StreamReader` from
|
|
|
|
accidentally calling inappropriate methods of the protocol.)
|
2014-01-23 10:05:01 +00:00
|
|
|
|
2014-01-23 10:25:48 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
Examples
|
|
|
|
========
|
2014-10-11 13:52:14 +00:00
|
|
|
|
2014-10-12 18:18:16 +00:00
|
|
|
.. _asyncio-tcp-echo-client-streams:
|
|
|
|
|
|
|
|
TCP echo client using streams
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
TCP echo client using the :func:`asyncio.open_connection` function::
|
|
|
|
|
|
|
|
import asyncio
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
async def tcp_echo_client(message):
|
|
|
|
reader, writer = await asyncio.open_connection(
|
|
|
|
'127.0.0.1', 8888)
|
2014-10-12 18:18:16 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
print(f'Send: {message!r}')
|
2014-10-12 18:18:16 +00:00
|
|
|
writer.write(message.encode())
|
|
|
|
|
2017-12-11 15:35:49 +00:00
|
|
|
data = await reader.read(100)
|
2018-09-11 16:54:40 +00:00
|
|
|
print(f'Received: {data.decode()!r}')
|
2014-10-12 18:18:16 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
print('Close the connection')
|
2014-10-12 18:18:16 +00:00
|
|
|
writer.close()
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
asyncio.run(tcp_echo_client('Hello World!'))
|
|
|
|
|
2014-10-12 18:18:16 +00:00
|
|
|
|
|
|
|
.. seealso::
|
|
|
|
|
|
|
|
The :ref:`TCP echo client protocol <asyncio-tcp-echo-client-protocol>`
|
2018-09-11 16:54:40 +00:00
|
|
|
example uses the low-level :meth:`loop.create_connection` method.
|
2014-10-12 18:18:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
.. _asyncio-tcp-echo-server-streams:
|
|
|
|
|
|
|
|
TCP echo server using streams
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
TCP echo server using the :func:`asyncio.start_server` function::
|
|
|
|
|
|
|
|
import asyncio
|
|
|
|
|
2017-12-11 15:35:49 +00:00
|
|
|
async def handle_echo(reader, writer):
|
|
|
|
data = await reader.read(100)
|
2014-10-12 18:18:16 +00:00
|
|
|
message = data.decode()
|
|
|
|
addr = writer.get_extra_info('peername')
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
print(f"Received {message!r} from {addr!r}")
|
|
|
|
|
|
|
|
print(f"Send: {message!r}")
|
2014-10-12 18:18:16 +00:00
|
|
|
writer.write(data)
|
2017-12-11 15:35:49 +00:00
|
|
|
await writer.drain()
|
2014-10-12 18:18:16 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
print("Close the connection")
|
2014-10-12 18:18:16 +00:00
|
|
|
writer.close()
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
async def main():
|
|
|
|
server = await asyncio.start_server(
|
|
|
|
handle_echo, '127.0.0.1', 8888)
|
|
|
|
|
|
|
|
addr = server.sockets[0].getsockname()
|
|
|
|
print(f'Serving on {addr}')
|
2014-10-12 18:18:16 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
async with server:
|
|
|
|
await server.serve_forever()
|
|
|
|
|
|
|
|
asyncio.run(main())
|
2014-10-12 18:18:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
.. seealso::
|
|
|
|
|
|
|
|
The :ref:`TCP echo server protocol <asyncio-tcp-echo-server-protocol>`
|
2018-09-11 16:54:40 +00:00
|
|
|
example uses the :meth:`loop.create_server` method.
|
2014-10-12 18:18:16 +00:00
|
|
|
|
|
|
|
|
2014-10-11 13:52:14 +00:00
|
|
|
Get HTTP headers
|
|
|
|
----------------
|
2014-01-23 10:25:48 +00:00
|
|
|
|
|
|
|
Simple example querying HTTP headers of the URL passed on the command line::
|
|
|
|
|
|
|
|
import asyncio
|
|
|
|
import urllib.parse
|
|
|
|
import sys
|
|
|
|
|
2018-08-07 20:29:06 +00:00
|
|
|
async def print_http_headers(url):
|
2014-01-23 10:25:48 +00:00
|
|
|
url = urllib.parse.urlsplit(url)
|
2014-10-11 13:52:14 +00:00
|
|
|
if url.scheme == 'https':
|
2018-09-11 16:54:40 +00:00
|
|
|
reader, writer = await asyncio.open_connection(
|
|
|
|
url.hostname, 443, ssl=True)
|
2014-10-11 13:52:14 +00:00
|
|
|
else:
|
2018-09-11 16:54:40 +00:00
|
|
|
reader, writer = await asyncio.open_connection(
|
|
|
|
url.hostname, 80)
|
|
|
|
|
|
|
|
query = (
|
|
|
|
f"HEAD {url.path or '/'} HTTP/1.0\r\n"
|
|
|
|
f"Host: {url.hostname}\r\n"
|
|
|
|
f"\r\n"
|
|
|
|
)
|
|
|
|
|
2014-01-23 10:25:48 +00:00
|
|
|
writer.write(query.encode('latin-1'))
|
|
|
|
while True:
|
2017-12-11 15:35:49 +00:00
|
|
|
line = await reader.readline()
|
2014-01-23 10:25:48 +00:00
|
|
|
if not line:
|
|
|
|
break
|
2018-09-11 16:54:40 +00:00
|
|
|
|
2014-01-23 10:25:48 +00:00
|
|
|
line = line.decode('latin1').rstrip()
|
|
|
|
if line:
|
2018-09-11 16:54:40 +00:00
|
|
|
print(f'HTTP header> {line}')
|
2014-01-23 10:25:48 +00:00
|
|
|
|
2014-10-11 13:52:14 +00:00
|
|
|
# Ignore the body, close the socket
|
|
|
|
writer.close()
|
|
|
|
|
2014-01-23 10:25:48 +00:00
|
|
|
url = sys.argv[1]
|
2018-09-11 16:54:40 +00:00
|
|
|
asyncio.run(print_http_headers(url))
|
|
|
|
|
2014-01-23 10:25:48 +00:00
|
|
|
|
|
|
|
Usage::
|
|
|
|
|
|
|
|
python example.py http://example.com/path/page.html
|
|
|
|
|
2014-10-11 14:16:27 +00:00
|
|
|
or with HTTPS::
|
|
|
|
|
|
|
|
python example.py https://example.com/path/page.html
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
|
2014-10-11 14:16:27 +00:00
|
|
|
.. _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
|
2018-09-11 16:54:40 +00:00
|
|
|
import socket
|
|
|
|
|
|
|
|
async def wait_for_data():
|
|
|
|
# Get a reference to the current event loop because
|
|
|
|
# we want to access low-level APIs.
|
|
|
|
loop = asyncio.get_running_loop()
|
2014-10-11 14:16:27 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
# Create a pair of connected sockets.
|
|
|
|
rsock, wsock = socket.socketpair()
|
2014-10-11 14:16:27 +00:00
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
# Register the open socket to wait for data.
|
|
|
|
reader, writer = await asyncio.open_connection(sock=rsock)
|
2014-10-11 14:16:27 +00:00
|
|
|
|
|
|
|
# Simulate the reception of data from the network
|
|
|
|
loop.call_soon(wsock.send, 'abc'.encode())
|
|
|
|
|
|
|
|
# Wait for data
|
2017-12-11 15:35:49 +00:00
|
|
|
data = await reader.read(100)
|
2014-10-11 14:16:27 +00:00
|
|
|
|
|
|
|
# Got data, we are done: close the socket
|
|
|
|
print("Received:", data.decode())
|
|
|
|
writer.close()
|
|
|
|
|
|
|
|
# Close the second socket
|
|
|
|
wsock.close()
|
|
|
|
|
2018-09-11 16:54:40 +00:00
|
|
|
asyncio.run(wait_for_data())
|
2014-10-11 14:16:27 +00:00
|
|
|
|
|
|
|
.. seealso::
|
|
|
|
|
|
|
|
The :ref:`register an open socket to wait for data using a protocol
|
2018-09-11 16:54:40 +00:00
|
|
|
<asyncio-register-socket>` example uses a low-level protocol and
|
|
|
|
the :meth:`loop.create_connection` method.
|
2014-10-11 14:16:27 +00:00
|
|
|
|
|
|
|
The :ref:`watch a file descriptor for read events
|
|
|
|
<asyncio-watch-read-event>` example uses the low-level
|
2018-09-11 16:54:40 +00:00
|
|
|
:meth:`loop.add_reader` method to watch a file descriptor.
|