An asyncio example

Adam Bartoš drekin at gmail.com
Sat Jul 4 08:20:01 EDT 2015


On Sat, Jul 4, 2015 at 1:07 PM, Adam Bartoš <drekin at gmail.com> wrote:

> On Fri, Jul 3, 2015 at 9:14 AM, Marko Rauhamaa <marko at pacujo.net>
>> wrote:
>> >
>> >>> 1) is there a way to close just one direction of the connection?
>> >>
>> >> No. SOCK_STREAM sockets are always bidirectional.
>> >
>> > socket.shutdown(socket.SHUT_WR) does the trick.
>> >
>> > I think the asyncio.StreamWriter.write_eof() is the high-level
>> > equivalent.
>>
>> I stand corrected. And you're also correct about write_eof: it causes
>> shutdown(SHUT_WR) to be called on the underlying socket once the
>> buffer has been written.
>>
>>
>> https://hg.python.org/cpython/file/34460219c0e0/Lib/asyncio/selector_events.py#l737
>>
>> That said, just replacing the writer.close() with writer.write_eof()
>> in the OP's code doesn't seem to work; the server response comes back
>> empty.
>>
>> This works:
>>
>> >>> sock1, sock2 = socket.socketpair()
>> >>> sock1.send(b'REQUEST')
>> 7
>> >>> sock1.shutdown(socket.SHUT_WR)
>> >>> sock2.recv(100)
>> b'REQUEST'
>> >>> sock2.send(b'RESPONSE')
>> 8
>> >>> sock1.recv(100)
>> b'RESPONSE'
>>
>> And this works:
>>
>> import asyncio
>> import socket
>>
>> def server(sock):
>>     request = yield from asyncio.get_event_loop().sock_recv(sock, 100)
>>     print("got request {!r}".format(request))
>>     yield from asyncio.get_event_loop().sock_sendall(sock, b'RESPONSE')
>>
>> def client(sock):
>>     yield from asyncio.get_event_loop().sock_sendall(sock, b'REQUEST')
>>     sock.shutdown(socket.SHUT_WR)
>>     response = yield from asyncio.get_event_loop().sock_recv(sock, 100)
>>     print("got response {!r}".format(response))
>>     asyncio.get_event_loop().stop()
>>
>> def connect():
>>     clientsock, serversock = socket.socketpair()
>>     clientsock.setblocking(False)
>>     serversock.setblocking(False)
>>     asyncio.async(client(clientsock))
>>     asyncio.async(server(serversock))
>>
>> connect()
>> asyncio.get_event_loop().run_forever()
>>
>> I'm wondering whether there might be a bug in the higher-level
>> transport code that interferes with reading after calling write_eof.
>
>
> There is a bug. See http://bugs.python.org/issue24539 .
>
>
The following code also works.

import asyncio
import socket

async def server(reader, writer):
    print("server is starting")

    print("server is going to receive a request")
    request = (await reader.read()).decode()
    print("server received request {!r}".format(request))

    response = "RESPONSE"
    writer.write(response.encode())
    print("server sent response {!r}".format(response))

    writer.write_eof()
    print("server sent EOF")

    print("server is finishing")

async def client(reader, writer):
    print("client is starting")

    request = "REQUEST"
    writer.write(request.encode())
    print("client sent request {!r}".format(request))

    writer.write_eof()
    print("client sent EOF")

    print("client is going to receive a response")
    response = (await reader.read()).decode()
    print("client received response {!r}".format(response))

    print("client is finishing")

class FixedStreamReaderProtocol(asyncio.StreamReaderProtocol):
    def eof_received(self):
        super().eof_received()
        return True # keep alive

async def open_connection(*, loop, sock):
    reader = asyncio.StreamReader(loop=loop)
    protocol = FixedStreamReaderProtocol(reader, loop=loop)
    transport, _ =  await loop.create_connection(lambda: protocol,
sock=sock)
    writer = asyncio.StreamWriter(transport, protocol, reader, loop)

    return reader, writer

async def connect(loop):
    serversock, clientsock = socket.socketpair()
    reader, writer = await open_connection(sock=serversock, loop=loop)
    server_coro = server(reader, writer)
    reader, writer = await open_connection(sock=clientsock, loop=loop)
    client_coro = client(reader, writer)

    server_task = loop.create_task(server_coro)
    client_task = loop.create_task(client_coro)

    return server_task, client_task

loop = asyncio.get_event_loop()
server_task, client_task = loop.run_until_complete(connect(loop))
loop.run_until_complete(server_task)
loop.run_until_complete(client_task)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20150704/2ba8dcbb/attachment.html>


More information about the Python-list mailing list