Clarify start_serving(). Add a section on coroutines and protocols.
This commit is contained in:
parent
3e3fce8960
commit
a3fa07058d
65
pep-3156.txt
65
pep-3156.txt
|
@ -224,14 +224,35 @@ Some methods return Futures:
|
|||
TBD: Signature. Do we pass in a protocol or protocol class?
|
||||
|
||||
- ``start_serving(...)``. Enters a loop that accepts connections.
|
||||
TBD: Signature. This definitely takes a protocol class. Do we pass
|
||||
in a non-blocking socket that's already bound and listening, or do
|
||||
we pass in arguments that let it create and configure the socket
|
||||
properly? (E.g. the event loop may know a better default backlog
|
||||
value for ``listen()`` than the typical application developer.)
|
||||
TBD: What does it return? Something we can use to stop accepting
|
||||
without stopping the event loop? A Future that completes when the
|
||||
socket is successfully accepting connections?
|
||||
TBD: Signature. There are two possibilities:
|
||||
|
||||
1. You pass it a non-blocking socket that you have already prepared
|
||||
with ``bind()`` and ``listen()`` (these system calls do not block
|
||||
AFAIK), a protocol factory (I hesitate to use this word :-), and
|
||||
optional flags that control the transport creation (e.g. ssl).
|
||||
|
||||
2. Instead of a socket, you pass it a host and port, and some more
|
||||
optional flags (e.g. to control IPv4 vs IPv6, or to set the
|
||||
backlog value to be passed to ``listen()``).
|
||||
|
||||
In either case, once it has a socket, it will wrap it in a
|
||||
transport, and then enter a loop accepting connections (the best way
|
||||
to implement such a loop depends on the platform). Each time a
|
||||
connection is accepted, a transport and protocol are created for it.
|
||||
|
||||
This should return an object that can be used to control the serving
|
||||
loop, e.g. to stop serving, abort all active connections, and (if
|
||||
supported) adjust the backlog or other parameters. It may also have
|
||||
an API to inquire about active connections. If version (2) is
|
||||
selected, it should probably return a Future whose result on success
|
||||
will be that control object, and which becomes done once the accept
|
||||
loop is started.
|
||||
|
||||
TBD: It may be best to use version (2), since on some platforms the
|
||||
best way to start a server may not involve sockets (but will still
|
||||
involve transports and protocols).
|
||||
|
||||
TBD: Be more specific.
|
||||
|
||||
The following methods for registering callbacks for file descriptors
|
||||
are optional. If they are not implemented, accessing the method
|
||||
|
@ -515,7 +536,7 @@ Protocols
|
|||
---------
|
||||
|
||||
Protocols are always used in conjunction with transports. While a few
|
||||
common protocols are provided (e.g. decent though not necessary
|
||||
common protocols are provided (e.g. decent though not necessarily
|
||||
excellent HTTP client and server implementations), most protocols will
|
||||
be implemented by user code or third-party libraries.
|
||||
|
||||
|
@ -588,6 +609,9 @@ it is perfectly fine to write code using callbacks only. On the other
|
|||
hand, there is only one implementation of the scheduler/coroutine API,
|
||||
and if you're using coroutines, that's the one you're using.
|
||||
|
||||
Coroutines
|
||||
----------
|
||||
|
||||
A coroutine is a generator that follows certain conventions. For
|
||||
documentation purposes, all coroutines should be decorated with
|
||||
``@tulip.coroutine``, but this cannot be strictly enforced.
|
||||
|
@ -595,8 +619,8 @@ documentation purposes, all coroutines should be decorated with
|
|||
Coroutines use the ``yield from`` syntax introduced in PEP 380,
|
||||
instead of the original ``yield`` syntax.
|
||||
|
||||
Unfortunately, the word "coroutine", like the word "generator", is
|
||||
used for two different (though related) concepts:
|
||||
The word "coroutine", like the word "generator", is used for two
|
||||
different (though related) concepts:
|
||||
|
||||
- The function that defines a coroutine (a function definition
|
||||
decorated with ``tulip.coroutine``). If disambiguation is needed,
|
||||
|
@ -678,6 +702,23 @@ implemented by the ``Task`` and ``Future`` classes using only the
|
|||
public interface of the event loop, so it will work with third-party
|
||||
event loop implementations, too.
|
||||
|
||||
Coroutines and Protocols
|
||||
------------------------
|
||||
|
||||
The best way to use coroutines to implement protocols is probably to
|
||||
use a streaming buffer that gets filled by ``data_received()`` and can
|
||||
be read asynchronously using methods like ``read(n)`` and
|
||||
``readline()`` that return a Future. When the connection is closed,
|
||||
``read()`` should return a Future whose result is ``b''``, or raise an
|
||||
exception if ``connection_closed()`` is called with an exception.
|
||||
|
||||
To write, the ``write()`` method (and friends) on the transport can be
|
||||
used -- these do not return Futures. A standard protocol
|
||||
implementation should be provided that sets this up and kicks off the
|
||||
coroutine when ``connection_made()`` is called.
|
||||
|
||||
TBD: Be more specific.
|
||||
|
||||
|
||||
Open Issues
|
||||
===========
|
||||
|
@ -722,7 +763,7 @@ Open Issues
|
|||
syntax). Anyway, I think all of these are easy enough to write
|
||||
using ``Task``.
|
||||
|
||||
- Priorities?
|
||||
- Task or callback priorities? (I hope not.)
|
||||
|
||||
|
||||
Acknowledgments
|
||||
|
|
Loading…
Reference in New Issue