有一个使用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.