So you're only concerned about the streams example, right? I modified this
so that wait_for_data() returns the 'rsock' object, which IIUC is what you
are concerned about (since it is handed to the transport and implicitly
closed by the writer.close() call). If I print this value right after the
run_until_complete() call, rsock is closed. I walked through this with pdb,
and I think that the following sequence of events happens:

- writer.close() calls self._transport.close(), which is
_SelectorTransport.close()
- that removes the socket from the selector and schedules a call to
_call_connection_lost
- wait_for_data() returns, causing the Task's result to be set, causing the
Task's callbacks to be scheduled
- the loop goes for the next event, which is _call_connection_lost
- _call_connection_lost() calls StreamReader.connection_lost(), which does
nothing interesting
- _call_connection_lost() then regains control and closes the socket (this
is what we've been waiting for!!!)
- after this the task's callback runs, which calls loop.stop(), which
causes the loop to stop, after any other callbacks that are still in the
loop's _ready queue

IOW I think this is working, but you're right in wondering how it works (it
wasn't easy to figure out). In a sense the key things are the way stop() is
implemented (by adding a callback to the _ready queue that raises
_StopError) and the way call_soon() promises to execute callbacks in the
order they were registered. However the PEP doesn't promise quite this --
the call_soon() promise is solid, but there are weasel-words for stop()
that allow it to exit from run_forever() before the _ready queue is empty.

I don't think you need to change the example, except you ought to decorate
wait_for_data() with @asyncio.coroutine. It's also true that TCP doesn't
guarantee that the recipient receives all three bytes in a single packet,
so the single read() call may not see all bytes, but I think even if
wait_for_data() closes the writer before everything has been read it will
still take the same flow (close() says to throw away unread bytes).

On Sun, Oct 12, 2014 at 12:29 AM, Victor Stinner <[email protected]>
wrote:

> Hi,
>
> I added 3 examples to show to to register an open sockets in asyncio
> documentation:
>
> add_register() with reader callback:
>
> https://docs.python.org/dev/library/asyncio-eventloop.html#asyncio-watch-read-event
>
> Protocol:
>
> https://docs.python.org/dev/library/asyncio-protocol.html#asyncio-register-socket
>
> Stream:
>
> https://docs.python.org/dev/library/asyncio-stream.html#register-an-open-socket-to-wait-for-data-using-streams
>
> I would like to ensure that all sockets are closed at the end of the
> example. For streams, I call writer.close(), but I don't see how to
> wait until the socket is closed. It doesn't look to be implemented
> directly. It looks like currently, it's only possible to call read()
> in a loop until read() returns an empty string:
>
> @asyncio.coroutine
> def  wait_eof(reader):
>     while True:
>         # Don't call read() becaues it may allocate a large buffer
>         data = yield from reader.read(4096)
>         if data:
>             break
>
> Is there another way to wait until the socket is closed? My wait_eof()
> looks complex, I don't want to put it in a simple example.
>
> Or maybe I should not wait until a socket is closed? Is it safe to
> call writer.close() and exit immediatly? The scheduled callback which
> will close the socket may not be called immediatly.
>
> Victor
>



-- 
--Guido van Rossum (python.org/~guido)

Reply via email to