Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #93463 > unrolled thread

Re: An asyncio example

Started byIan Kelly <ian.g.kelly@gmail.com>
First post2015-07-03 08:31 -0600
Last post2015-07-03 23:58 -0600
Articles 3 — 2 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: An asyncio example Ian Kelly <ian.g.kelly@gmail.com> - 2015-07-03 08:31 -0600
    Re: An asyncio example Marko Rauhamaa <marko@pacujo.net> - 2015-07-03 18:14 +0300
      Re: An asyncio example Ian Kelly <ian.g.kelly@gmail.com> - 2015-07-03 23:58 -0600

#93463 — Re: An asyncio example

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-07-03 08:31 -0600
SubjectRe: An asyncio example
Message-ID<mailman.273.1435933923.3674.python-list@python.org>
On Fri, Jul 3, 2015 at 4:28 AM, Adam Bartoš <drekin@gmail.com> wrote:
> Hello,
>
> I'm experimenting with asyncio. I have composed the following code. There is
> a server handler and a client handler. I didn't want to split the code into
> two files so I just used a socketpair, inspired by example
> https://docs.python.org/3/library/asyncio-stream.html#register-an-open-socket-to-wait-for-data-using-streams
> . However, my code doesn't work – it blocks because both sides are trying to
> read more data. But if I close the writer on one side (the commented line),
> whole connection is closed. So
>
> 1) is there a way to close just one direction of the connection?

No. SOCK_STREAM sockets are always bidirectional.

> 2) In the blocked situaction even KeyboardInterrupt doesn't break the loop,
> is that desired behavior? And why?

I don't think so. When I tried this locally (using Python 3.4.0, so
replacing "async def" with "def" and "await" with "yield from" and
"loop.create_task" with "asyncio.async") pressing Ctrl-C did interrupt
the loop.

> 3) Are there some other issues with my code with respect to “best practices”
> how to write a code like this?

There are a couple of approaches you could take. Since your protocol
is so far text-based, I would suggest adding '\n' to the ends of your
messages and using reader.readline instead of reader.read.
Alternatively, since the writer isn't planning to write anything
further after its one message, just call writer.write_eof() (not
writer.close) after the call to write.

[toc] | [next] | [standalone]


#93465

FromMarko Rauhamaa <marko@pacujo.net>
Date2015-07-03 18:14 +0300
Message-ID<87vbe1qnn6.fsf@elektro.pacujo.net>
In reply to#93463
>> 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.


Marko

[toc] | [prev] | [next] | [standalone]


#93481

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-07-03 23:58 -0600
Message-ID<mailman.286.1435989573.3674.python-list@python.org>
In reply to#93465
On Fri, Jul 3, 2015 at 9:14 AM, Marko Rauhamaa <marko@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.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web