前言websocket是一种网络传输协议。可以通过单个TCP连接进行全双工通信。基于此,websocket使得客户端和服务器之间的通信更加简单高效。什么是websocketwebsocket是一个建立在TCP之上的独立协议。该协议诞生于2008年,2011年成为国际标准,其主要特点之一是全双工,即一旦建立连接,服务器或客户端就可以主动向对方推送消息。在websocket出现之前,如果网站需要实现push技术,都是采用轮询的方式,即浏览器每隔一段时间向服务器发送一次请求。这种模式的缺点是浏览器需要不断地向服务器发送请求,消耗了大量的带宽资源。虽然比较新的Comet技术也可以实现双向通信,但是仍然需要重复发送请求,而且Comet常用的HTTP长连接也会消耗服务器资源。基于以上情况,HTML5定义了websocket协议,可以更好的节省服务器和带宽资源。并实现高效的实时通信。目前,所有浏览器都支持它。websocket通信的原理和机制虽然websocket是一个新的协议,但是它不能脱离http而独立存在。客户端在构建websocket实例连接服务端时,首先会发起http消息请求。告诉服务器需要将通信协议切换为websocket。如果服务端支持websocket协议,则将通信协议切换为websocket并返回响应信息。此时返回状态码为101,表示同意协议转换请求,可以进行数据传输。websocket之所以使用HTTP来完成握手协议,是因为兼容性好。默认端口为80和443。握手阶段不容易被防火墙阻止。websocket的特点是开销小。服务器端和客户端交互数据时,协议包头包含的信息少,实时性高。协议采用全双工。相对于客户端发起请求,服务端即可响应的http请求方式,延迟明显更低,对HTTP的兼容性较好,默认端口为80和443。握手使用HTTP协议,不易被防火墙拦截。支持文本和二进制数据传输。支持自定义扩展。用户可以实现自己的自定义子协议。通过心跳机制保持服务端与客户端的长连接。构建一个实时日志跟踪的小例子。启动一个监听日志脚本的服务,该服务会限制允许访问的路径范围(防止黑客利用程序漏洞扫描整个服务器);服务器通过分析客户端的请求,将日志消息内容返回给客户端;服务器定期向客户端发送心跳检测。如果客户端收不到客户端的响应,就会断开与服务器的连接。核心程序代码逻辑如下withopen(file_path)asf:#第一次读取指定行数(NUM_LINES)的日志文件,发送给客户端。content=''.join(deque(f,NUM_LINES))content=conv.convert(content,full=False)awaitwebsocket.send(content)#如果发现客户端有tail请求,则执行taillogtrackingiftail:#首先创建本次请求的心跳时间last_heartbeat=time.time()whileTrue:#每次tail服务端最新的日志记录,返回给客户端content=f.read()ifcontent:content=conv.convert(content,full=False)awaitwebsocket.send(content)else:awaitasyncio.sleep(1)#检测本次请求是否超过自上次请求以来的最长心跳检测时间,若超过则发起心跳检测如果time.time()-last_heartbeat>HEARTBEAT_INTERVAL:try:awaitwebsocket.send('ping')pong=awaitasyncio.wait_for(websocket.recv(),5)logger.info(f"pong:{pong}")ifpong!='pong':raiseException()exceptException:raiseException('Pingerror')else:last_heartbeat=time.time()else:awaitwebsocket.close()客户端很简单,监听服务端日志文件,如果发现有新的日志,输出日志或者直接在前端页面实时显示日志相应的,如果需要长期监控,当服务端发送心跳检测信号时,也需要响应心跳反馈。客户端核心代码逻辑如下:asyncdefconsumer_handler(websocket:WebSocketClientProtocol)->None:asyncformessageinwebsocket:log_message(message)ifmessage=="ping":awaitwebsocket.send("pong")asyncdefcousume(hostname:str,port:int,log_file:str,tail:bool=True)->None:websocket_resource_url=f"ws://{hostname}:{port}{log_file}"iftail:websocket_resource_url=f"{websocket_resource_url}?tail=1"asyncwithwebsockets.connect(websocket_resource_url)aswebsocket:awaitconsumer_handler(websocket)deflog_message(message:str)->None:logger.info(f"Message:{message}")这里模拟一个日志生产文件代码逻辑如下self.folder如果不是os.path.exists(self.folder):os.mkdir(self.folder)self.file=self.folder+'/'+文件名logger.add(self.file,rotation="100MB")@propertydefget_logger(self):returnloggerif__name__=='__main__':logger=LoggerExtend(os.path.basename(__file__).replace(".py",".log")).get_loggerimporttimewhileTrue:logger.info("Helloaaa")最后启动日志生产程序→服务器程序→客户端后启动终端程序日志制作文件,运行效果如下。服务器启动程序运行,不产生运行日志。此时启动客户端程序,运行效果如下。此时服务器会生成相应的操作日志,如下图。完整代码请移至GitHub查看https://github.com/hacksman/l...日志生产程序路径:common/logger_extend.py服务器程序路径:websoctet_lab/log_server.py客户端程序路径:websoctet_lab/cousumer_log_view.py参考资料[1]如何在Python中创建WebSocket[2]如何在Python中创建WebSocket[3]WebSocket教程[4]WebSocket-基于Python_LIN的博客-CSDN博客的主流实现总结[5]GoEasy|更简单的Websocket|Web消息推送专家[6]PythonWebSocket客户端实现[7]理论联系实际:从零社区看懂WebSocket通信原理、协议格式和安全![8]WebSocket详解(一):WebSocket技术初探-网页IM开发/专题技术专区-即时通讯开发者社区![9]使用WebSocket和Python的LogTailer
