异步错误:CLI-python守护程序示例,但在退出时出现错误/不希望的行为



我开发了一个模式,用于通过cmd模块外壳使用eventloop命令python守护进程。然而,它还没有准备好,因为我不知道如何优雅地退出这两个应用程序(我仍在学习asyncio,无法解决以下问题(。当命令cmd模块退出时,我得到:

(Cmd) exit
Shutting down client...
Traceback (most recent call last):
File "client_loop.py", line 10, in <module>
loop.run_until_complete(test.cmdloop())
File "...asynciobase_events.py", line 467, in run_until_complete
future = tasks.ensure_future(future, loop=self)
File "...libasynciotasks.py", line 526, in ensure_future
raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required

我还不擅长asyncio,我做错了什么?很抱歉问了这么长的问题,但文件/错误会让问题变得很长,希望能让调试变得更容易。

以下是支持文件:

shell.py

# implementation of the (Cmd) prompt with history functionality
# standard imports
import cmd as cmd
class Shell(cmd.Cmd):
def __init__(self, **kwargs):
cmd.Cmd.__init__(self, **kwargs)
self.eventloop = None
self.shutdown_client = None
self.tcp_echo_client = None

def set_eventloop(self, loop):
self.eventloop = loop

def set_funcs(self, tcp_echo_client, shutdown_client):
self.tcp_echo_client = tcp_echo_client
self.shutdown_client = shutdown_client
def do_exit(self,*args):
"""
Exits the shell gracefully
:param args:
:return:
"""
print('Shutting down client...')
self.shutdown_client(self.eventloop)
return True
def default(self, line):
try:
self.eventloop.run_until_complete(self.tcp_echo_client(line, self.eventloop))
except SystemExit:
pass

服务器.py

# server logic to parse arguments coming over the TCP socket and echo it back
# standard imports
import asyncio
async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr))
print("Send: %r" % message)
writer.write(data)
await writer.drain()
print("Close the client socket")
writer.close()
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
# Close the server
for task in asyncio.Task.all_tasks():
loop.run_until_complete(task)
server.close()
loop.run_until_complete(server.wait_closed())
loop.stop()
loop.close()
exit(0)

客户端.py

# client functions to send message over TCP and process response
# standard imports
import asyncio
# user imports
import shell
async def tcp_echo_client(message, loop):
reader, writer = await asyncio.open_connection('127.0.0.1', 8888,
loop=loop)
print('Send: %r' % message)
writer.write(message.encode())
data = await reader.read(100)
print('Received: %r' % data.decode())
print('Close the socket')
writer.close()
def shutdown_client(loop):
loop.stop()
# Find all running tasks:
pending = asyncio.Task.all_tasks()
# Run loop until tasks done:
loop.run_until_complete(asyncio.gather(*pending))
loop = asyncio.get_event_loop()
test = shell.Shell()
test.set_eventloop(loop)
test.set_funcs(tcp_echo_client, shutdown_client)
loop.run_until_complete(test.cmdloop())
loop.close()

问题在于cmd不需要asyncio来处理来自用户的输入并通过TCP/IP套接字向发送消息。简单地从客户端删除asyncio就解决了这个问题。它仍然提供shell实现和客户端-服务器模式。这是新代码:

服务器.py

# server logic to parse arguments coming over the TCP socket and echo it back
# standard imports
import asyncio
async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr))
print("Send: %r" % message)
writer.write(data)
await writer.drain()
print("Close the client socket")
writer.close()
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
# Close the server
for task in asyncio.Task.all_tasks():
loop.run_until_complete(task)
server.close()
loop.run_until_complete(server.wait_closed())
loop.stop()
loop.close()
exit(0)

client_shell.py

# implementation of a shell prompt (using Cmd module) to send message over TCP and process response
# standard imports
import socket
import cmd as cmd
class Shell(cmd.Cmd):
def __init__(self, **kwargs):
cmd.Cmd.__init__(self, **kwargs)
def do_exit(self,*args):
"""
Exits the shell gracefully
:param args:
:return:
"""
print('Shutting down client...')
return True
def default(self, line):
try:
self._tcp_echo_client(line.encode())
except SystemExit:
pass
def _tcp_echo_client(self, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
print('Send: %r' % message)
s.connect(('127.0.0.1', 8888))
s.sendall(message)
data = s.recv(1000)
print('Received: %r' % data.decode())
print('Close the socket')
if __name__ == '__main__':
Shell().cmdloop()

相关内容

最新更新