使用asyncio的Python网络

使用asyncio的Python网络,python,networking,Python,Networking,所以我正在学习如何制作一个简单的聊天应用程序,但这是作业的一部分,我必须使用asyncio。问题是,当客户端按下Ctrl-C时,会出现运行时错误,我不知道如何修复它 第二个问题是,当服务器终止时,客户端挂起,等待用户输入;相比之下,我希望客户 也可以在打印后终止,服务器刚刚关闭连接。 以下是服务器的代码: import sys, asyncio all_clients = set([]) @asyncio.coroutine def handle_connection(reader, wri

所以我正在学习如何制作一个简单的聊天应用程序,但这是作业的一部分,我必须使用asyncio。问题是,当客户端按下Ctrl-C时,会出现运行时错误,我不知道如何修复它 第二个问题是,当服务器终止时,客户端挂起,等待用户输入;相比之下,我希望客户 也可以在打印后终止,服务器刚刚关闭连接。 以下是服务器的代码:

import sys, asyncio

all_clients = set([])

@asyncio.coroutine
def handle_connection(reader, writer):
    all_clients.add(writer)
    client_addr = writer.get_extra_info('peername')
    print('New client {}'.format(client_addr))
    while True:
        data = yield from reader.read(100)
        if data == None or len(data) == 0:
            break
        message = data.decode()
        print("Received {} from {}".format(message, client_addr))
        for other_writer in all_clients:
            if other_writer != writer:
                new_message = '{} says: {}'.format(client_addr,data)
                other_writer.write(new_message.encode())
                yield from other_writer.drain()
    all_clients.remove(writer)
    print("Close the client socket")
    yield from writer.drain()
    writer.close()

def run():
    loop = asyncio.get_event_loop()
    coro = asyncio.start_server(handle_connection,'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:
        print('\nGot keyboard interrupt, shutting down',file=sys.stderr)
        sys.exit()
    for task in asyncio.Task.all_tasks():
        task.cancel()
    server.close()
    loop.run_until_complete(server.wait_closed())
    loop.close()    

if __name__ == '__main__':
    run()
以下是客户端的代码:

import sys, asyncio
import aioconsole

class NoneException(Exception):
    pass

class ClosingException(Exception):
    pass

@asyncio.coroutine
def open_connection(loop):
    reader, writer = yield from asyncio.open_connection('127.0.0.1',
                                                     8888,loop=loop)
    return reader, writer

@asyncio.coroutine
def use_connection(reader, writer):
    yield from asyncio.gather(read_from_network(reader,writer),
                                        send_to_server(writer))

@asyncio.coroutine
def read_from_network(reader,writer):
    while True:
        net_message = yield from reader.read(100)
        if writer.transport.is_closing():
            print('Terminating read from network.')
            break
        elif net_message == None:
            continue
        elif len(net_message) == 0:
            print('The server closed the connection.')
            writer.close()
            break
        print('\nReceived: %r' % net_message.decode())
        print('>> ',end='',flush=True)

@asyncio.coroutine
def send_to_server(writer):
    try:
        while True:
            original_message = yield from aioconsole.ainput('>> ')
            if original_message != None:
                console_message = original_message.strip()
                if console_message == '':
                    continue
                if console_message == 'close()' or \
                            writer.transport.is_closing():
                    raise ClosingException()
                writer.write(console_message.encode())
    except ClosingException:
        print('Got close() from user.')
    finally:
        if not writer.transport.is_closing():
            writer.close()

def run():
    try:
        loop = asyncio.get_event_loop()
        reader,writer=loop.run_until_complete(open_connection(loop))
        loop.run_until_complete(use_connection(reader,writer))
    except KeyboardInterrupt:
        print('Got Ctrl-C from user.')
    except Exception as e:
        print(e,file=sys.stderr)
    finally:
        loop.close()


if __name__ == '__main__':
    run()
以下是客户端按下Ctrl-C时引发的详细信息或运行时错误

^来自用户的CGot Ctrl-C。 在中忽略异常: 回溯(最近一次呼叫最后一次): 文件“client.py”,第56行,发送到服务器 文件“/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/streams.py”,第306行,关闭 文件“/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/selector_events.py”,第622行,关闭 文件“/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base\u events.py”,第573行,即将调用 文件“/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base\u events.py”,第357行,in\u check\u closed RuntimeError:事件循环已关闭

用户
writer.close()
,然后关闭事件循环。无需在
send\u to\u server
方法中关闭它

def run():
   try:
      loop = asyncio.get_event_loop()
      reader,writer=loop.run_until_complete(open_connection(loop))
      loop.run_until_complete(use_connection(reader,writer))
   except KeyboardInterrupt:
       print('Got Ctrl-C from user.')

       # closing writer before the event loop
       writer.close()
   except Exception as e:
       print(e,file=sys.stderr)
   finally:
       loop.close()