<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Jul 4, 2015 at 1:07 PM, Adam Bartoš <span dir="ltr"><<a href="mailto:drekin@gmail.com" target="_blank">drekin@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><blockquote style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex" class="gmail_quote"><span class="">On Fri, Jul 3, 2015 at 9:14 AM, Marko Rauhamaa <marko at <a href="http://pacujo.net" target="_blank">pacujo.net</a>> wrote:<br>><br>>>> 1) is there a way to close just one direction of the connection?<br>>><br></span><span class="">>> No. SOCK_STREAM sockets are always bidirectional.<br>><br></span><span class="">> socket.shutdown(socket.SHUT_WR) does the trick.<br>><br>> I think the asyncio.StreamWriter.write_eof() is the high-level<br>> equivalent.<br><br></span>I stand corrected. And you're also correct about write_eof: it causes<br>shutdown(SHUT_WR) to be called on the underlying socket once the<br>buffer has been written.<br><br><a href="https://hg.python.org/cpython/file/34460219c0e0/Lib/asyncio/selector_events.py#l737" target="_blank">https://hg.python.org/cpython/file/34460219c0e0/Lib/asyncio/selector_events.py#l737</a><br><br>That said, just replacing the writer.close() with writer.write_eof()<br>in the OP's code doesn't seem to work; the server response comes back<br>empty.<br><br>This works:<br><br>>>> sock1, sock2 = socket.socketpair()<br>>>> sock1.send(b'REQUEST')<br>7<br>>>> sock1.shutdown(socket.SHUT_WR)<br>>>> sock2.recv(100)<br>b'REQUEST'<br>>>> sock2.send(b'RESPONSE')<br>8<br>>>> sock1.recv(100)<br>b'RESPONSE'<br><br>And this works:<br><br>import asyncio<br>import socket<br><br>def server(sock):<br>    request = yield from asyncio.get_event_loop().sock_recv(sock, 100)<span class=""><br>    print("got request {!r}".format(request))<br></span>    yield from asyncio.get_event_loop().sock_sendall(sock, b'RESPONSE')<br><br>def client(sock):<br>    yield from asyncio.get_event_loop().sock_sendall(sock, b'REQUEST')<br>    sock.shutdown(socket.SHUT_WR)<br>    response = yield from asyncio.get_event_loop().sock_recv(sock, 100)<span class=""><br>    print("got response {!r}".format(response))<br></span>    asyncio.get_event_loop().stop()<br><br>def connect():<br>    clientsock, serversock = socket.socketpair()<br>    clientsock.setblocking(False)<br>    serversock.setblocking(False)<br>    asyncio.async(client(clientsock))<br>    asyncio.async(server(serversock))<br><br>connect()<br>asyncio.get_event_loop().run_forever()<br><br>I'm wondering whether there might be a bug in the higher-level<br>transport code that interferes with reading after calling write_eof.</blockquote><div><br></div><div>There is a bug. See <a href="http://bugs.python.org/issue24539" target="_blank">http://bugs.python.org/issue24539</a> .<br><br></div></div>
</blockquote></div><br></div><div class="gmail_extra">The following code also works.<br><br>import asyncio<br>import socket<br><br>async def server(reader, writer):<br>    print("server is starting")<br>    <br>    print("server is going to receive a request")<br>    request = (await reader.read()).decode()<br>    print("server received request {!r}".format(request))<br>    <br>    response = "RESPONSE"<br>    writer.write(response.encode())<br>    print("server sent response {!r}".format(response))<br>    <br>    writer.write_eof()<br>    print("server sent EOF")<br>    <br>    print("server is finishing")<br><br>async def client(reader, writer):<br>    print("client is starting")<br>    <br>    request = "REQUEST"<br>    writer.write(request.encode())<br>    print("client sent request {!r}".format(request))<br>    <br>    writer.write_eof()<br>    print("client sent EOF")<br>    <br>    print("client is going to receive a response")<br>    response = (await reader.read()).decode()<br>    print("client received response {!r}".format(response))<br>    <br>    print("client is finishing")<br><br>class FixedStreamReaderProtocol(asyncio.StreamReaderProtocol):<br>    def eof_received(self):<br>        super().eof_received()<br>        return True # keep alive<br><br>async def open_connection(*, loop, sock):<br>    reader = asyncio.StreamReader(loop=loop)<br>    protocol = FixedStreamReaderProtocol(reader, loop=loop)<br>    transport, _ =  await loop.create_connection(lambda: protocol, sock=sock)<br>    writer = asyncio.StreamWriter(transport, protocol, reader, loop)<br>    <br>    return reader, writer<br><br>async def connect(loop):<br>    serversock, clientsock = socket.socketpair()<br>    reader, writer = await open_connection(sock=serversock, loop=loop)<br>    server_coro = server(reader, writer)<br>    reader, writer = await open_connection(sock=clientsock, loop=loop)<br>    client_coro = client(reader, writer)<br>    <br>    server_task = loop.create_task(server_coro)<br>    client_task = loop.create_task(client_coro)<br>    <br>    return server_task, client_task<br><br>loop = asyncio.get_event_loop()<br>server_task, client_task = loop.run_until_complete(connect(loop))<br>loop.run_until_complete(server_task)<br>loop.run_until_complete(client_task)<br><br></div></div>