From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.3 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,NUMERIC_HTTP_ADDR,SPF_HELO_NONE, SPF_PASS,WEIRD_PORT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9CA3DC636C9 for ; Wed, 21 Jul 2021 19:56:08 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F2C7661208 for ; Wed, 21 Jul 2021 19:56:07 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F2C7661208 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:46976 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1m6IK6-0000df-O5 for qemu-devel@archiver.kernel.org; Wed, 21 Jul 2021 15:56:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35784) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1m6IJP-0008Ln-Jj for qemu-devel@nongnu.org; Wed, 21 Jul 2021 15:55:23 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:53776) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1m6IJL-0002G5-2z for qemu-devel@nongnu.org; Wed, 21 Jul 2021 15:55:21 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1626897317; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=3aVimnrgWFCsjhA+6drfWIX3Olb7DVJWrehZnlITWjE=; b=VBxmAM5SK3YbYtm6U1DvjZn89rnD2HeKCr9Ew/cjt86w6p0uEnCXr9lnP0mEQwid+VO/hW W7x3vWyyo64ZzfAQIbnfs4TFXgJ59xGJqbc/NeR2i5EOwQx3eJC5JVI1gW8BDrjpwGgWxs bTfLgAzycEBw8vhxJ8ZVyX7MSIOXTOs= Received: from mail-oo1-f69.google.com (mail-oo1-f69.google.com [209.85.161.69]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-522-QW78NNwlPUiB6-FGEigELw-1; Wed, 21 Jul 2021 15:55:15 -0400 X-MC-Unique: QW78NNwlPUiB6-FGEigELw-1 Received: by mail-oo1-f69.google.com with SMTP id j3-20020a4a94430000b029025c2496941aso1585354ooi.10 for ; Wed, 21 Jul 2021 12:55:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=3aVimnrgWFCsjhA+6drfWIX3Olb7DVJWrehZnlITWjE=; b=C5kFcj5SEBtSLax26Loo+1r+gm5TytyBjO1TZzPnxzWwnAesVxt/tQBZ6pu4dD1VPs nEZDCCweTA7Cl93sLDZqN6jutyNzTAZbIBdbmIiC6zqP8/KepeA3VQyNuwH4xF1KkMj4 fLEbVtvBn1U78oDbWmGrZFuxFoHi4IwSrLRAt7AXbCLF3A7ljQsYCw1r6YcPgSOWRixS q+Oc/7bIWrEFpKfsjli88sa59+mwL/XOf50mesjua2bYpG63+pMylfGixAsfTXWA7Djc pls6krXjGJ+fDjaQRD1ChaF488zLxTncQwphkwyo+IZzIn9pOIINKMlP6u0sYbjzsNQa WNgg== X-Gm-Message-State: AOAM5307VjC0abXvakBvhi1PHNCV+1MxopBMx+Z6x1vovCzP6XVeMa2c fniyRaPZGlEMTbLSig2hE5wOSMuhg7KIvprbdTeHrHIlzV9ydOxTU7EHw2+l7D1SRXhAmydIq+O ld/bRR7R/7PS/9xw8MdoDbtJjaWOljms= X-Received: by 2002:a9d:20a2:: with SMTP id x31mr25758799ota.263.1626897314839; Wed, 21 Jul 2021 12:55:14 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz6udb2YLXTo6wkkXcH8Djf8pcN82t3bIIF3KE5E3ni99XgWxSmbpAE3sPPsYdkZKCvfhcsfe2qHVCsg6J2Xzo= X-Received: by 2002:a9d:20a2:: with SMTP id x31mr25758785ota.263.1626897314631; Wed, 21 Jul 2021 12:55:14 -0700 (PDT) MIME-Version: 1.0 References: <20210717003253.457418-1-jsnow@redhat.com> In-Reply-To: From: John Snow Date: Wed, 21 Jul 2021 15:55:03 -0400 Message-ID: Subject: Re: [PATCH v2 00/24] python: introduce Asynchronous QMP package To: "Niteesh G. S." Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: multipart/alternative; boundary="0000000000008668a005c7a78caf" Received-SPF: pass client-ip=170.10.133.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -29 X-Spam_score: -3.0 X-Spam_bar: --- X-Spam_report: (-3.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.459, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, NUMERIC_HTTP_ADDR=1.242, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, WEIRD_PORT=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eduardo Habkost , Stefan Hajnoczi , qemu-devel , Wainer dos Santos Moschetta , Markus Armbruster , Willian Rampazzo , Cleber Rosa , Eric Blake Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --0000000000008668a005c7a78caf Content-Type: text/plain; charset="UTF-8" Looping qemu-devel back in: I removed them by accident by not hitting reply-all :( On Wed, Jul 21, 2021 at 2:06 PM Niteesh G. S. wrote: > > > On Wed, Jul 21, 2021 at 11:03 PM John Snow wrote: > >> >> >> On Wed, Jul 21, 2021 at 1:04 PM Niteesh G. S. >> wrote: >> >>> Hello all, >>> >>> I recently rebased(incrementally) my TUI on this V2 patch and faced an >>> issue. >>> https://gitlab.com/niteesh.gs/qemu/-/commits/aqmp-tui-prototype-v3 >>> I decided to rebase incrementally so that I can address some of the >>> comments posted >>> in my patch series. While testing out, the initial draft of TUI >>> which worked fine in the V1 >>> version of AQMP failed in this version. >>> >>> Disconnecting from a fully connected state doesn't exit cleanly. >>> >>> --------------------------------------------------------------------------------- >>> To reproduce the issue: >>> 1) Initiate a QMP server >>> >> >> Please provide the command line. >> > qemu-system-x86_64 -qmp tcp:localhost:1234,server,wait=on > >> >> >>> 2) Connect the TUI to the server using aqmp-tui localhost:1234 >>> --log-file log.txt >>> >> >> The entry point isn't defined yet in your series, so I will assume >> "python3 -m qemu.aqmp.aqmp_tui localhost:1234" should work here. >> > Yup, sorry about that. I realized this later when recreated the venv. > >> >> >>> 3) Once the TUI is connected and running, press 'Esc' to exit the app. >>> This should result >>> in the following exception. >>> >>> -------------------------------------------------------------------------------------------------------------------------------------------- >>> Transitioning from 'Runstate.IDLE' to 'Runstate.CONNECTING'. >>> Connecting to ('localhost', 1234) ... >>> Connected. >>> Awaiting greeting ... >>> Response: { >>> "QMP": { >>> .......... Skipping >>> } >>> } >>> Negotiating capabilities ... >>> Request: { >>> "execute": "qmp_capabilities", >>> .......... Skipping >>> } >>> } >>> Response: { >>> "return": {} >>> } >>> Transitioning from 'Runstate.CONNECTING' to 'Runstate.RUNNING'. >>> Transitioning from 'Runstate.RUNNING' to 'Runstate.DISCONNECTING'. >>> Scheduling disconnect. >>> Draining the outbound queue ... >>> Flushing the StreamWriter ... >>> Cancelling writer task ... >>> Task.Writer: cancelled. >>> Task.Writer: exiting. >>> Cancelling reader task ... >>> Task.Reader: cancelled. >>> Task.Reader: exiting. >>> Closing StreamWriter. >>> Waiting for StreamWriter to close ... >>> QMP Disconnected. >>> Transitioning from 'Runstate.DISCONNECTING' to 'Runstate.IDLE'. >>> _kill_app: Connection lost >>> Connection lost >>> | Traceback (most recent call last): >>> | File >>> "/home/niteesh/development/qemu/python/qemu/aqmp/aqmp_tui.py", line 246, in >>> run >>> | main_loop.run() >>> | File >>> "/home/niteesh/development/qemu/python/.venv/lib/python3.6/site-packages/urwid/main_loop.py", >>> line 287, in run >>> | self._run() >>> | File >>> "/home/niteesh/development/qemu/python/.venv/lib/python3.6/site-packages/urwid/main_loop.py", >>> line 385, in _run >>> | self.event_loop.run() >>> | File >>> "/home/niteesh/development/qemu/python/.venv/lib/python3.6/site-packages/urwid/main_loop.py", >>> line 1494, in run >>> | reraise(*exc_info) >>> | File >>> "/home/niteesh/development/qemu/python/.venv/lib/python3.6/site-packages/urwid/compat.py", >>> line 58, in reraise >>> | raise value >>> | File >>> "/home/niteesh/development/qemu/python/qemu/aqmp/aqmp_tui.py", line 206, in >>> _kill_app >>> | raise err >>> | File >>> "/home/niteesh/development/qemu/python/qemu/aqmp/aqmp_tui.py", line 201, in >>> _kill_app >>> | await self.disconnect() >>> | File >>> "/home/niteesh/development/qemu/python/qemu/aqmp/protocol.py", line 303, in >>> disconnect >>> | await self._wait_disconnect() >>> | File >>> "/home/niteesh/development/qemu/python/qemu/aqmp/protocol.py", line 573, in >>> _wait_disconnect >>> | await self._dc_task >>> | File >>> "/home/niteesh/development/qemu/python/qemu/aqmp/qmp_client.py", line 316, >>> in _bh_disconnect >>> | await super()._bh_disconnect() >>> | File >>> "/home/niteesh/development/qemu/python/qemu/aqmp/protocol.py", line 644, in >>> _bh_disconnect >>> | await wait_closed(self._writer) >>> | File "/home/niteesh/development/qemu/python/qemu/aqmp/util.py", >>> line 137, in wait_closed >>> | await flush(writer) >>> | File "/home/niteesh/development/qemu/python/qemu/aqmp/util.py", >>> line 49, in flush >>> | await writer.drain() >>> | File "/usr/lib/python3.6/asyncio/streams.py", line 339, in drain >>> | yield from self._protocol._drain_helper() >>> | File "/usr/lib/python3.6/asyncio/streams.py", line 210, in >>> _drain_helper >>> | raise ConnectionResetError('Connection lost') >>> | ConnectionResetError: Connection lost >>> >>> -------------------------------------------------------------------------------------------------------------------------------------------- >>> >>> >> I can't reproduce in Python 3.9, but I *can* reproduce in python 3.6 >> using the pipenv environment; i.e. >> >> > make check-pipenv >> > pipenv shell >> > python3 -m qemu.aqmp.aqmp_tui 127.0.0.1:1234 >> >> What python version are you using to see this failure? Is it 3.6 ? >> > Yes, I was using python 3.6. I just tried it on 3.8 and I don't face this > issue. > >> >> It seems like the wait_closed() wrapper I wrote isn't quite compatible >> with Python 3.6, it looks like it's not really safe to try and flush a >> closing socket. I was doing so in an attempt to tell when the socket had >> finished closing out its buffer (expecting it to normally be a no-op) but >> in this case even a no-op drain in 3.6 seems to raise an error if we >> attempt it after we've asked for the socket to close. >> > > >> wait_closed() was added in Python 3.7 and we just don't have access to it >> here ... I'm not sure if there's something else we can do here to serve as >> a workaround for not having this function. >> >> --js >> >> I can't find a *nice* workaround, but I found one that should probably work in most universes. We can remove this ugly code when we support 3.7 as a minimum. However, please try this patch as a fixup: diff --git a/python/qemu/aqmp/util.py b/python/qemu/aqmp/util.py index de0df44cbd7..eaa5fc7d5f9 100644 --- a/python/qemu/aqmp/util.py +++ b/python/qemu/aqmp/util.py @@ -134,7 +134,17 @@ async def wait_closed(writer: asyncio.StreamWriter) -> None: while not transport.is_closing(): await asyncio.sleep(0) - await flush(writer) + + # This is an ugly workaround, but it's the best I can come up with. + sock = transport.get_extra_info('socket') + + if sock is None: + # Our transport doesn't have a socket? ... + # Nothing we can reasonably do. + return + + while sock.fileno() != -1: + await asyncio.sleep(0) --0000000000008668a005c7a78caf Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Looping qemu-devel back in: I removed them by acciden= t by not hitting reply-all :(

On Wed, Jul 21, 2021 at 2:06 PM Niteesh G.= S. <niteesh.gs@gmail.com>= ; wrote:

<= br>
On Wed,= Jul 21, 2021 at 11:03 PM John Snow <jsnow@redhat.com> wrote:


On= Wed, Jul 21, 2021 at 1:04 PM Niteesh G. S. <niteesh.gs@gmail.com> wrote:
Hello all,

=
I recently rebased(incrementally) my T= UI on this V2 patch and faced an issue.
https://gitlab.com/niteesh.gs/qemu/-/commits/aqmp-tu= i-prototype-v3
I decided to rebase incrementally so that I can addre= ss some of the comments posted
in my pa= tch series. While testing out, the initial=C2=A0draft of TUI which=C2=A0wor= ked fine in the V1
version of AQMP fail= ed in this version.

Disconnecting from a fully connected state doesn'= t exit cleanly.
-----------------------= ----------------------------------------------------------
To reproduce the issue:
1) Initiate a QMP server

= Please provide the command line.
qemu-system-x86= _64 -qmp tcp:localhost:1234,server,wait=3Don
<= /div>
=C2=A0
2) Connect the TUI to the serv= er using aqmp-tui=C2=A0localhost:1234 --log-file log.txt

The entry point isn't defined yet in your ser= ies, so I will assume "python3 -m qemu.aqmp.aqmp_tui localhost:1234&qu= ot; should work here.
Yup, sorry about that. I realized= this later when recreated the venv.=C2=A0
<= div>
=C2=A0
3) Once the TUI is connec= ted and running, press 'Esc' to exit the app. This should result
in the following exception.
----------------------------------------------------= ---------------------------------------------------------------------------= -------------
Transitioning from 'R= unstate.IDLE' to 'Runstate.CONNECTING'.
Connecting to ('= localhost', 1234) ...
Connected.
Awaiting greeting ...
Respons= e: {
=C2=A0 "QMP": {
=C2=A0 =C2=A0 .......... Skipping
= =C2=A0 }
}
Negotiating capabilities ...
Request: {
=C2=A0 "= ;execute": "qmp_capabilities",
=C2=A0 =C2=A0 .......... S= kipping
=C2=A0 }
}
Response: {
=C2=A0 "return": {}}
Transitioning from 'Runstate.CONNECTING' to 'Runstate.RUN= NING'.
Transitioning from 'Runstate.RUNNING' to 'Runstat= e.DISCONNECTING'.
Scheduling disconnect.
Draining the outbound qu= eue ...
Flushing the StreamWriter ...
Cancelling writer task ...
T= ask.Writer: cancelled.
Task.Writer: exiting.
Cancelling reader task .= ..
Task.Reader: cancelled.
Task.Reader: exiting.
Closing StreamWri= ter.
Waiting for StreamWriter to close ...
QMP Disconnected.
Trans= itioning from 'Runstate.DISCONNECTING' to 'Runstate.IDLE'.<= br>_kill_app: Connection lost
Connection lost
=C2=A0 | Traceback (mos= t recent call last):
=C2=A0 | =C2=A0 File "/home/niteesh/developmen= t/qemu/python/qemu/aqmp/aqmp_tui.py", line 246, in run
=C2=A0 | =C2= =A0 =C2=A0 main_loop.run()
=C2=A0 | =C2=A0 File "/home/niteesh/deve= lopment/qemu/python/.venv/lib/python3.6/site-packages/urwid/main_loop.py&qu= ot;, line 287, in run
=C2=A0 | =C2=A0 =C2=A0 self._run()
=C2=A0 | =C2= =A0 File "/home/niteesh/development/qemu/python/.venv/lib/python3.6/si= te-packages/urwid/main_loop.py", line 385, in _run
=C2=A0 | =C2=A0 = =C2=A0 self.event_loop.run()
=C2=A0 | =C2=A0 File "/home/niteesh/de= velopment/qemu/python/.venv/lib/python3.6/site-packages/urwid/main_loop.py&= quot;, line 1494, in run
=C2=A0 | =C2=A0 =C2=A0 reraise(*exc_info)
= =C2=A0 | =C2=A0 File "/home/niteesh/development/qemu/python/.venv/lib/= python3.6/site-packages/urwid/compat.py", line 58, in reraise
=C2= =A0 | =C2=A0 =C2=A0 raise value
=C2=A0 | =C2=A0 File "/home/niteesh= /development/qemu/python/qemu/aqmp/aqmp_tui.py", line 206, in _kill_ap= p
=C2=A0 | =C2=A0 =C2=A0 raise err
=C2=A0 | =C2=A0 File "/home/n= iteesh/development/qemu/python/qemu/aqmp/aqmp_tui.py", line 201, in _k= ill_app
=C2=A0 | =C2=A0 =C2=A0 await self.disconnect()
=C2=A0 | =C2= =A0 File "/home/niteesh/development/qemu/python/qemu/aqmp/protocol.py&= quot;, line 303, in disconnect
=C2=A0 | =C2=A0 =C2=A0 await self._wait_d= isconnect()
=C2=A0 | =C2=A0 File "/home/niteesh/development/qemu/py= thon/qemu/aqmp/protocol.py", line 573, in _wait_disconnect
=C2=A0 |= =C2=A0 =C2=A0 await self._dc_task
=C2=A0 | =C2=A0 File "/home/nite= esh/development/qemu/python/qemu/aqmp/qmp_client.py", line 316, in _bh= _disconnect
=C2=A0 | =C2=A0 =C2=A0 await super()._bh_disconnect()
=C2= =A0 | =C2=A0 File "/home/niteesh/development/qemu/python/qemu/aqmp/pro= tocol.py", line 644, in _bh_disconnect
=C2=A0 | =C2=A0 =C2=A0 await= wait_closed(self._writer)
=C2=A0 | =C2=A0 File "/home/niteesh/deve= lopment/qemu/python/qemu/aqmp/util.py", line 137, in wait_closed
= =C2=A0 | =C2=A0 =C2=A0 await flush(writer)
=C2=A0 | =C2=A0 File "/h= ome/niteesh/development/qemu/python/qemu/aqmp/util.py", line 49, in fl= ush
=C2=A0 | =C2=A0 =C2=A0 await writer.drain()
=C2=A0 | =C2=A0 File = "/usr/lib/python3.6/asyncio/streams.py", line 339, in drain
= =C2=A0 | =C2=A0 =C2=A0 yield from self._protocol._drain_helper()
=C2=A0 = | =C2=A0 File "/usr/lib/python3.6/asyncio/streams.py", line 210, = in _drain_helper
=C2=A0 | =C2=A0 =C2=A0 raise ConnectionResetError('= Connection lost')
=C2=A0 | ConnectionResetError: Connection lost
=
----------------------------------------------------------------------= ----------------------------------------------------------------------

I can't reproduce in Python 3.9, but I *can* reproduce in p= ython 3.6 using the pipenv environment; i.e.

> = make check-pipenv
> pipenv shell
> python3 -m qem= u.aqmp.aqmp_tui 127.0.0= .1:1234

What python version are you using to s= ee this failure? Is it 3.6 ?
Yes, I was using python 3.6. I= just tried it on 3.8 and I don't face this issue.

It seems like the wait_closed() wrapper I wr= ote isn't quite compatible with Python 3.6, it looks like it's not = really safe to try and flush a closing socket. I was doing so in an attempt= to tell when the socket had finished closing out its buffer (expecting it = to normally be a no-op) but in this case even a no-op drain in 3.6 seems to= raise an error if we attempt it after we've asked for the socket to cl= ose.
=C2=A0
wait_closed() was added in Python 3.7 and we just don't have access to= it here ... I'm not sure if there's something else we can do here = to serve as a workaround for not having this function.

=
--js


I can't find a *nice* workaround, but I fo= und one that should probably work in most universes. We can remove this ugl= y code when we support 3.7 as a minimum. However, please try this patch as = a fixup:

diff --git a/python/qemu/aqmp/util.py b/p= ython/qemu/aqmp/util.py
index de0df44cbd7..eaa5fc7d5f9 100644
--- a/p= ython/qemu/aqmp/util.py
+++ b/python/qemu/aqmp/util.py
@@ -134,7 +134= ,17 @@ async def wait_closed(writer: asyncio.StreamWriter) -> None:
= =C2=A0
=C2=A0 =C2=A0 =C2=A0while not transport.is_closing():
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0await asyncio.sleep(0)
- =C2=A0 =C2=A0await f= lush(writer)
+
+ =C2=A0 =C2=A0# This is an ugly workaround, but it= 9;s the best I can come up with.
+ =C2=A0 =C2=A0sock =3D transport.get_e= xtra_info('socket')
+
+ =C2=A0 =C2=A0if sock is None:
+ = =C2=A0 =C2=A0 =C2=A0 =C2=A0# Our transport doesn't have a socket? ...+ =C2=A0 =C2=A0 =C2=A0 =C2=A0# Nothing we can reasonably do.
+ =C2=A0 = =C2=A0 =C2=A0 =C2=A0return
+
+ =C2=A0 =C2=A0while sock.fileno() !=3D = -1:
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0await asyncio.sleep(0)

=C2=A0
--0000000000008668a005c7a78caf--