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)
