如何用Python实现客户端打印服务端监测到的日志变更(模拟tail -f)
问题根因
- Tail类默认回调是
sys.stdout.write,初始化时未传入发送到socket的回调函数,所有日志内容直接输出到服务端控制台,没有发往客户端
- Tail类默认回调是
follow()方法是永久阻塞的死循环,无任何返回值,你调用clientsocket.send(bytes(py_tail.follow(10),"utf-8"))这行代码永远无法获得要发送的内容,也不会执行后续逻辑
- 客户端代码中
msg.decode("utf-8")未保存解码结果,直接打印原始bytes对象,就算收到数据显示格式也错误
- 客户端代码中
- 服务端单线程逻辑只能同时处理一个客户端连接,阻塞在
follow逻辑后无法响应其他操作
- 服务端单线程逻辑只能同时处理一个客户端连接,阻塞在
修复后代码
server.py
import socket import sys import threading s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((socket.gethostname(), 1243)) s.listen(5) class Tail(): def __init__(self,file_name,callback=sys.stdout.write): self.file_name = file_name self.callback = callback def follow(self,n): try: with open(self.file_name) as f: self._file = f self.showLastLine(n) self._file.seek(0,2) while True: line = self._file.readline() if line: self.callback(line) except Exception as e: print('Failed to open the file. See if the file does not exist or if there is a problem with permissions') print(e) def showLastLine(self, n): last_lines = self._file.readlines()[-10:] for line in last_lines: self.callback(line) # 处理单个客户端连接的函数 def handle_client(clientsocket): # 定义回调函数,收到新日志直接发给客户端 def send_to_client(line): try: clientsocket.send(line.encode("utf-8")) except: # 客户端断开连接时结束 clientsocket.close() return py_tail = Tail('log.log', callback=send_to_client) py_tail.follow(10) while True: clientsocket, address = s.accept() print(f"新客户端连接:{address}") # 每个连接单独开线程处理,不阻塞主进程 client_thread = threading.Thread(target=handle_client, args=(clientsocket,)) client_thread.daemon = True client_thread.start()
client.py
import socket import sys s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((socket.gethostname(), 1243)) while True: msg = s.recv(1024) if not msg: # 服务端断开连接时退出 break # 保存解码后的内容再打印 content = msg.decode("utf-8") print(content, end='')
测试说明
先启动服务端,再启动客户端,此时客户端会先打印log.log的最后10行内容,之后你新增的日志内容会实时推送到客户端打印。
内容的提问来源于stack exchange,提问作者Glen Veigas
相关产品推荐
相关产品推荐

