断开连接后如何关闭客户端流?

时间:2019-09-30 12:20:26

标签: multithreading python-3.7 python-asyncio

有一个使用Python的asyncio库的简单聊天程序。客户端可以进行通信,而不会受到任何操作的阻碍。此外,每当客户端连接/断开与服务器的连接时,服务器会将信息输出到控制台窗口。此外,客户端的所有活动均由服务器写入日志文件。

当我查看控制台窗口时,没有明显的问题。客户端断开连接一秒钟后,有关该客户端的信息将写入服务器的控制台窗口。但是,当我查看日志文件时,可以看到服务器正在尝试向所有连接的客户端发送空消息。但是这些消息不会显示在客户端的窗口中。

如此看来,服务器未正确关闭断开连接的客户端。即使客户端断开连接,断开连接的客户端的读取器和写入器流也似乎处于活动状态。

如何根据我共享的代码解决此问题?顺便说一句,我也共享日志文件。这是代码:

server.py

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

import asyncio
import logging

logging.basicConfig(
    filename="server.log",
    format="- %(levelname)s - %(asctime)s - %(message)s", 
    level=logging.DEBUG,
    datefmt="%d.%m.%Y %H:%M:%S"
    )    


class Server:

    def __init__(self):
        self.clients = []

    def run(self):
        asyncio.run(self.main())

    async def client_connected(self, reader, writer):
        client = f"{writer.get_extra_info('peername')}"
        print(f"{client} is connected.")
        logging.info(f"{client} is connected.")
        self.clients.append((writer, reader))
        while True:
            try:
                data = await reader.readline()
            except (BrokenPipeError, ConnectionResetError):
                data = "".encode()
                await asyncio.sleep(1)
            for i in self.clients:
                msg = f"{client}: {data.decode()}"
                try:
                    i[0].write(msg.encode())
                    logging.debug(msg[:-1])
                    await i[0].drain()
                except (BrokenPipeError, ConnectionResetError):
                    i[0].close()
                    self.clients.remove(i)
                    print(f"{client} is disconnected.")
                    logging.info(f"{client} is disconnected.")
                    await asyncio.sleep(2)
                    break

    async def main(self):
        server = await asyncio.start_server(
            client_connected_cb=self.client_connected,
            host="127.0.0.1",
            port=12345
        )
        print(f"Server started on {server.sockets[0].getsockname()}")
        logging.info(f"Server started on {server.sockets[0].getsockname()}")
        async with server:
            await server.wait_closed()


if __name__ == "__main__":
    Server().run()

client.py

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

import sys
import asyncio
import threading


class Client:

    def __init__(self):
        self.nick = input("/nick ")
        while not self.nick:
            self.nick = input("/nick ")

    def run(self):
        asyncio.run(self.main())

    async def read(self, reader, writer):
        data = await reader.readline()
        socket = writer.get_extra_info('socket').getsockname()
        if str(socket) not in data.decode() or \
                self.nick not in data.decode():
            if data.decode().count("('") >= 1:
                data = data.decode().split(": ")[-2:]
                print(": ".join(data)[:-1])

    async def write(self, writer):
        t = threading.Thread(
            target=lambda: writer.write(
                f"{self.nick}: {sys.stdin.readline()}".encode()
            )
        )
        t.daemon = True
        t.start()
        t.join(0.1)
        await writer.drain()

    async def main(self):
        reader, writer = await asyncio.open_connection("127.0.0.1", 12345)
        print(f"Connected to {writer.get_extra_info('peername')}")
        while reader and writer:
            await asyncio.gather(
                self.read(reader, writer), 
                self.write(writer)
            )


if __name__ == "__main__":
    Client().run()

server.log

- DEBUG - 30.09.2019 15:17:50 - Using selector: EpollSelector
- INFO - 30.09.2019 15:17:50 - Server started on ('127.0.0.1', 12345)
- INFO - 30.09.2019 15:17:56 - ('127.0.0.1', 45562) is connected.
- INFO - 30.09.2019 15:18:05 - ('127.0.0.1', 45564) is connected.
- INFO - 30.09.2019 15:18:21 - ('127.0.0.1', 45566) is connected.
- DEBUG - 30.09.2019 15:18:48 - ('127.0.0.1', 45566): Client3: Hello Clients!
- DEBUG - 30.09.2019 15:18:48 - ('127.0.0.1', 45566): Client3: Hello Clients!
- DEBUG - 30.09.2019 15:18:48 - ('127.0.0.1', 45566): Client3: Hello Clients!
- DEBUG - 30.09.2019 15:18:51 - ('127.0.0.1', 45566): Client3: How are you?
- DEBUG - 30.09.2019 15:18:51 - ('127.0.0.1', 45566): Client3: How are you?
- DEBUG - 30.09.2019 15:18:51 - ('127.0.0.1', 45566): Client3: How are you?
- DEBUG - 30.09.2019 15:18:53 - ('127.0.0.1', 45566):
- DEBUG - 30.09.2019 15:18:53 - ('127.0.0.1', 45566):
- DEBUG - 30.09.2019 15:18:53 - ('127.0.0.1', 45566):
- DEBUG - 30.09.2019 15:18:53 - ('127.0.0.1', 45566):
- DEBUG - 30.09.2019 15:18:53 - ('127.0.0.1', 45566):
- DEBUG - 30.09.2019 15:18:53 - ('127.0.0.1', 45566):
- INFO - 30.09.2019 15:18:53 - ('127.0.0.1', 45566) is disconnected.
- DEBUG - 30.09.2019 15:18:55 - ('127.0.0.1', 45564):
- DEBUG - 30.09.2019 15:18:55 - ('127.0.0.1', 45564):
- DEBUG - 30.09.2019 15:18:55 - ('127.0.0.1', 45564):
- DEBUG - 30.09.2019 15:18:55 - ('127.0.0.1', 45564):
- INFO - 30.09.2019 15:18:55 - ('127.0.0.1', 45564) is disconnected.
- DEBUG - 30.09.2019 15:18:56 - ('127.0.0.1', 45566):
- DEBUG - 30.09.2019 15:18:57 - ('127.0.0.1', 45562):
- DEBUG - 30.09.2019 15:18:57 - ('127.0.0.1', 45562):
- INFO - 30.09.2019 15:18:57 - ('127.0.0.1', 45562) is disconnected.

0 个答案:

没有答案