python制作服务器信息监控的api,支持多平台,基于flask和socketio

您所在的位置:网站首页 django监控多个服务器状态 python制作服务器信息监控的api,支持多平台,基于flask和socketio

python制作服务器信息监控的api,支持多平台,基于flask和socketio

#python制作服务器信息监控的api,支持多平台,基于flask和socketio| 来源: 网络整理| 查看: 265

system-info-api

python的系统信息web api。包括restful和socketio,以及获取系统硬件信息的函数。 这些接口方便绘制可视化图表

项目地址:https://github.com/Pure-Peace/system-info-api

支持windows,linux多平台

Python system information web api. Including restful and socketio, convenient to draw visual charts

说明

此项目包含基于flask的restful api以及socketio,分为两种方式提供服务。

系统信息:背景线程将会每间隔数秒更新系统信息(cpu、内存、硬盘、负载等),并在本地进行缓存,缓存形式包括json文件以及内存(变量)。主动推送:每当背景线程更新系统信息,socketio将会广播这些系统信息数据。被动获取:你可以通过访问web api来主动获取已经缓存的系统信息,这些缓存信息会随着背景线程的运行而更新。 也就是说,服务器监控页面只需要在首次加载的时候访问web api获取已缓存的(历史)系统信息一次,剩下的图表更新均由socketio进行推送数据更新。

省资源,而且实时性高。

文件分为三部分 main.py

包含背景线程以及flask、socketio。

''' @author: Pure-Peace @name: 系统信息 @time: 2020年8月17日 @version: 0.1 ''' import systemInfo from utils import log, getTime from gevent import monkey; monkey.patch_all() import threading import time import json from flask_socketio import SocketIO from flask import Flask, jsonify, request from flask_cors import CORS # fix: windows cmd cannot display colors from colorama import init init(autoreset=True) # initial(s) app = Flask(__name__) #app.config['SECRET_KEY'] = 'asdqwezxc' app.config.update(RESTFUL_JSON=dict(ensure_ascii=False)) app.config["JSON_AS_ASCII"] = False # 跨域 CORS(app) socketio = SocketIO() socketio.init_app(app, cors_allowed_origins='*', async_mode='gevent') class Cache: def __init__(self, name: str, limit: int = 30): ''' 缓存 Parameters ---------- name : str 缓存名称,关系到文件保存. limit : int, optional 缓存上限,最高存储多少条信息. The default is 30. Returns ------- None. ''' self.name = name self.limit = limit self.read() def add(self, item): ''' 添加数据到缓存中 Parameters ---------- item : TYPE DESCRIPTION. Returns ------- None. ''' if len(self.data) >= self.limit: del(self.data[0]) self.data.append(item) self.save() def save(self): ''' 将缓存持久化,存储到name对应的json文件中 Returns ------- None. ''' try: with open(f'{self.name}.json', 'w', encoding='utf-8') as file: json.dump(self.data, file, indent=4) except: pass def read(self): ''' 读取缓存(如果有) Returns ------- None. ''' try: with open(f'{self.name}.json', 'r', encoding='utf-8') as file: self.data = json.load(file) except: self.data = [] # apis ------------------------------- @app.route('/') def root(): return jsonify({'status': 1, 'message': 'hello'}) @app.route('/cpu_constants') def cpuConstants(): return jsonify(cpuData) @app.route('/cpu_info') def cpuInfo(): return jsonify(cpuCache.data) @app.route('/io_info') def ioInfo(): return jsonify(ioCache.data) @app.route('/mem_info') def memInfo(): return jsonify(memCache.data) @app.route('/network_info') def networkInfo(): return jsonify(networkCache.data) @app.route('/load_info') def loadInfo(): return jsonify(loadCache.data) # socketio ------------------------------- @socketio.on('disconnect') def sioDisconnect(): log('socketio连接断开:', request.remote_addr) @socketio.on('connect') def sioConnect(): log('socketio连接建立:', request.remote_addr) # 背景线程 ------------------------------- def cpuBackground(interval: int = 8) -> None: ''' 更新cpu信息并更新缓存,同时向前端socketio推送信息 Parameters ---------- interval : int, optional 间隔多少时间更新一次cpu信息. The default is 8. Returns ------- None DESCRIPTION. ''' def task(): data: dict = systemInfo.GetCpuInfo(constants = False) # 获取cpu信息 cpuCache.add(data) # 更新缓存 socketio.emit('update_cpu', data, broadcast=True) # 推送信息,事件名为update_cpu loopRun(task, interval) # 循环执行,每隔interval秒执行一次 def ioBackground(interval: int = 5) -> None: def task(): data: dict = systemInfo.GetIoReadWrite() ioCache.add(data) socketio.emit('update_io', data, broadcast=True) loopRun(task, interval) def memBackground(interval: int = 5) -> None: def task(): data: dict = systemInfo.GetMemInfo() memCache.add(data) socketio.emit('update_mem', data, broadcast=True) loopRun(task, interval) def networkBackground(interval: int = 5) -> None: def task(): data: dict = systemInfo.GetNetWork() networkCache.add(data) socketio.emit('update_net', data, broadcast=True) loopRun(task, interval) def loadBackground(interval: int = 5) -> None: def task(): data: dict = systemInfo.GetLoadAverage() loadCache.add(data) socketio.emit('update_load', data, broadcast=True) loopRun(task, interval) def loopRun(func, interval: int, *arg, **kwargs) -> None: ''' 循环执行 Parameters ---------- func : TYPE 要执行的函数. interval : int 间隔时间. *arg : TYPE 位置参数. **kwargs : TYPE 关键字参数. Returns ------- None DESCRIPTION. ''' while True: try: time.sleep(interval) func(*arg, **kwargs) except Exception as err: log('循环线程执行异常:', err) # 线程列表 ts: list = [ threading.Thread(target=cpuBackground), threading.Thread(target=ioBackground), threading.Thread(target=memBackground), threading.Thread(target=networkBackground), threading.Thread(target=loadBackground) ] # 获取cpu常量信息 cpuData = systemInfo.cpuConstants.getDict # 建立缓存 cpuCache = Cache('cpuInfo') ioCache = Cache('ioInfo') memCache = Cache('memInfo') networkCache = Cache('networkInfo') loadCache = Cache('loadInfo') if __name__ == '__main__': # 开启所有线程 for t in ts: t.start() log('应用已启动') # 启动app(危险:0.0.0.0将使得外网可直接访问) socketio.run(app, host = '0.0.0.0', port = 5678) systemInfo.py

systemInfo.py模块中包含所有可用的系统信息函数(所有api可以在此处找到,包含一些说明) 项目地址:https://github.com/Pure-Peace/system-info

# -*- coding: utf-8 -*- ''' @name: 系统信息 / SystemInfo @author: PurePeace @time: 2020年8月17日 @version: 0.1 ''' from typing import List, Dict, Any from utils import log, getTime import os import time import psutil import platform import hashlib import re import sys from cachelib import SimpleCache cache = SimpleCache() UNIX: bool = os.name == 'posix' SYS: str = platform.system() class CpuConstants: def __init__(self): ''' 初始化CPU常量(多平台) Returns ------- self. ''' self.WMI = None self.initialed: bool = False self.cpuList: list = [] # windows only self.cpuCount: int = 0 # 物理cpu数量 self.cpuCore: int = 0 # cpu物理核心数 self.cpuThreads: int = 0 # cpu逻辑核心数 self.cpuName: str = '' # cpu型号 self.Update(True) def Update(self, update: bool = False) -> None: ''' 更新cpu数据 Returns ------- None. ''' log('正在更新cpu常量...') if UNIX: self.GetCpuConstantsUnix(update) else: self.GetCpuConstantsWindows(update) log('更新完毕!') self.initialed: bool = True @property def getDict(self) -> Dict[int, str]: ''' 以字典格式获取当前cpu常量 Returns ------- Dict[int, str] DESCRIPTION. ''' if not self.initialed: self.Update() return { 'cpu_count': self.cpuCount, 'cpu_name': self.cpuName, 'cpu_core': self.cpuCore, 'cpu_threads': self.cpuThreads } def GetCpuConstantsUnix(self, update: bool = False) -> None: ''' 获取unix下的cpu信息 Parameters ---------- update : bool, optional DESCRIPTION. The default is False. Returns ------- None DESCRIPTION. ''' if update or not self.initialed: ids: list = re.findall("physical id.+", readFile('/proc/cpuinfo')) # 物理cpu个数 self.cpuCount: int = len(set(ids)) # cpu型号(名称) self.cpuName: str = self.getCpuTypeUnix() self.GetCpuConstantsBoth() def InitWmi(self) -> None: ''' 初始化wmi(for windows) Returns ------- None DESCRIPTION. ''' import wmi self.WMI = wmi.WMI() def GetCpuConstantsBoth(self, update: bool = False) -> None: ''' 获取多平台共用的cpu信息 Parameters ---------- update : bool, optional 强制更新数据. The default is False. Returns ------- None DESCRIPTION. ''' if update or not self.initialed: # cpu逻辑核心数 self.cpuThreads: int = psutil.cpu_count() # cpu物理核心数 self.cpuCore: int = psutil.cpu_count(logical=False) def GetCpuConstantsWindows(self, update: bool = False) -> None: ''' 获取windows平台的cpu信息 Parameters ---------- update : bool, optional 强制更新数据. The default is False. Returns ------- None DESCRIPTION. ''' if update or not self.initialed: # 初始化wmi if self.WMI == None: self.InitWmi() # cpu列表 self.cpuList: list = self.WMI.Win32_Processor() # 物理cpu个数 self.cpuCount: int = len(self.cpuList) # cpu型号(名称) self.cpuName: str = self.cpuList[0].Name self.GetCpuConstantsBoth() @staticmethod def getCpuTypeUnix() -> str: ''' 获取CPU型号(unix) Returns ------- str CPU型号. ''' cpuinfo: str = readFile('/proc/cpuinfo') rep: str = 'model\s+name\s+:\s+(.+)' tmp = re.search(rep,cpuinfo,re.I) cpuType: str = '' if tmp: cpuType: str = tmp.groups()[0] else: cpuinfo = ExecShellUnix('LANG="en_US.UTF-8" && lscpu')[0] rep = 'Model\s+name:\s+(.+)' tmp = re.search(rep,cpuinfo,re.I) if tmp: cpuType = tmp.groups()[0] return cpuType def GetCpuInfo(interval: int = 1, constants: bool = True) -> Dict[str, Any]: ''' 获取CPU信息 Parameters ---------- interval : int, optional DESCRIPTION. The default is 1. Returns ------- Dict[float, list, dict] DESCRIPTION. ''' time.sleep(0.5) # cpu总使用率 used: float = psutil.cpu_percent(interval) # 每个逻辑cpu使用率 usedList: List[float] = psutil.cpu_percent(percpu=True) return {'used': used, 'used_list': usedList, **(cpuConstants.getDict if constants else {})} def readFile(filename: str) -> str: ''' 读取文件内容 Parameters ---------- filename : str 文件名. Returns ------- str 文件内容. ''' try: with open(filename, 'r', encoding='utf-8') as file: return file.read() except: pass return '' def GetLoadAverage() -> dict: ''' 获取服务器负载状态(多平台) Returns ------- dict DESCRIPTION. ''' try: c: list = os.getloadavg() except: c: list = [0,0,0] data: dict = {i: c[idx] for idx, i in enumerate(('one', 'five', 'fifteen'))} data['max'] = psutil.cpu_count() * 2 data['limit'] = data['max'] data['safe'] = data['max'] * 0.75 return data def GetMemInfo() -> dict: ''' 获取内存信息(多平台) Returns ------- dict DESCRIPTION. ''' if UNIX: return GetMemInfoUnix() return GetMemInfoWindows() def GetMemInfoUnix() -> Dict[str, int]: ''' 获取内存信息(unix) Returns ------- dict DESCRIPTION. ''' mem = psutil.virtual_memory() memInfo: dict = { 'memTotal': ToSizeInt(mem.total, 'MB'), 'memFree': ToSizeInt(mem.free, 'MB'), 'memBuffers': ToSizeInt(mem.buffers, 'MB'), 'memCached': ToSizeInt(mem.cached, 'MB'), } memInfo['memRealUsed'] = \ memInfo['memTotal'] - \ memInfo['memFree'] - \ memInfo['memBuffers'] - \ memInfo['memCached'] memInfo['memUsedPercent'] = memInfo['memRealUsed'] / memInfo['memTotal'] * 100 return memInfo def GetMemInfoWindows() -> dict: ''' 获取内存信息(windows) Returns ------- dict DESCRIPTION. ''' mem = psutil.virtual_memory() memInfo: dict = { 'memTotal': ToSizeInt(mem.total, 'MB'), 'memFree': ToSizeInt(mem.free, 'MB'), 'memRealUsed': ToSizeInt(mem.used, 'MB'), 'menUsedPercent': mem.used / mem.total * 100 } return memInfo def ToSizeInt(byte: int, target: str) -> int: ''' 将字节大小转换为目标单位的大小 Parameters ---------- byte : int int格式的字节大小(bytes size) target : str 目标单位,str. Returns ------- int 转换为目标单位后的字节大小. ''' return int(byte/1024**(('KB','MB','GB','TB').index(target) + 1)) def ToSizeString(byte: int) -> str: ''' 获取字节大小字符串 Parameters ---------- byte : int int格式的字节大小(bytes size). Returns ------- str 自动转换后的大小字符串,如:6.90 GB. ''' units: tuple = ('b','KB','MB','GB','TB') re = lambda: '{:.2f} {}'.format(byte, u) for u in units: if byte list: ''' 获取磁盘信息(多平台) Returns ------- list 列表. ''' try: if UNIX: return GetDiskInfoUnix() return GetDiskInfoWindows() except Exception as err: log('获取磁盘信息异常(unix: {}):'.format(UNIX), err) return [] def GetDiskInfoWindows() -> list: ''' 获取磁盘信息Windows Returns ------- diskInfo : list 列表. ''' diskIo: list = psutil.disk_partitions() diskInfo: list = [] for disk in diskIo: tmp: dict = {} try: tmp['path'] = disk.mountpoint.replace("\\","/") usage = psutil.disk_usage(disk.mountpoint) tmp['size'] = { 'total': usage.total, 'used': usage.used, 'free': usage.free, 'percent': usage.percent } tmp['fstype'] = disk.fstype tmp['inodes'] = False diskInfo.append(tmp) except: pass return diskInfo def GetDiskInfoUnix() -> list: ''' 获取硬盘分区信息(unix) Returns ------- list DESCRIPTION. ''' temp: list = ( ExecShellUnix("df -h -P|grep '/'|grep -v tmpfs")[0]).split('\n') tempInodes: list = ( ExecShellUnix("df -i -P|grep '/'|grep -v tmpfs")[0]).split('\n') diskInfo: list = [] n: int = 0 cuts: list = [ '/mnt/cdrom', '/boot', '/boot/efi', '/dev', '/dev/shm', '/run/lock', '/run', '/run/shm', '/run/user' ] for tmp in temp: n += 1 try: inodes: list = tempInodes[n-1].split() disk: list = tmp.split() if len(disk) 10: continue if disk[5] in cuts: continue if disk[5].find('docker') != -1: continue arr = {} arr['path'] = disk[5] tmp1 = [disk[1],disk[2],disk[3],disk[4]] arr['size'] = tmp1 arr['inodes'] = [inodes[1],inodes[2],inodes[3],inodes[4]] diskInfo.append(arr) except Exception as ex: log('信息获取错误:', str(ex)) continue return diskInfo def md5(strings: str) -> str: ''' 生成md5 Parameters ---------- strings : TYPE 要进行hash处理的字符串 Returns ------- str[32] hash后的字符串. ''' m = hashlib.md5() m.update(strings.encode('utf-8')) return m.hexdigest() def GetErrorInfo() -> str: ''' 获取traceback中的错误 Returns ------- str DESCRIPTION. ''' import traceback errorMsg = traceback.format_exc() return errorMsg def ExecShellUnix(cmdstring: str, shell=True): ''' 执行Shell命令(Unix) Parameters ---------- cmdstring : str DESCRIPTION. shell : TYPE, optional DESCRIPTION. The default is True. Returns ------- a : TYPE DESCRIPTION. e : TYPE DESCRIPTION. ''' a: str = '' e: str = '' import subprocess,tempfile try: rx: str = md5(cmdstring) succ_f = tempfile.SpooledTemporaryFile( max_size = 4096, mode = 'wb+', suffix = '_succ', prefix = 'btex_' + rx , dir = '/dev/shm' ) err_f = tempfile.SpooledTemporaryFile( max_size = 4096, mode = 'wb+', suffix = '_err', prefix = 'btex_' + rx , dir = '/dev/shm' ) sub = subprocess.Popen( cmdstring, close_fds = True, shell = shell, bufsize = 128, stdout = succ_f, stderr = err_f ) sub.wait() err_f.seek(0) succ_f.seek(0) a = succ_f.read() e = err_f.read() if not err_f.closed: err_f.close() if not succ_f.closed: succ_f.close() except Exception as err: log(err) try: if type(a) == bytes: a = a.decode('utf-8') if type(e) == bytes: e = e.decode('utf-8') except Exception as err: log(err) return a,e def GetNetWork() -> dict: ''' 获取系统网络信息 Returns ------- dict DESCRIPTION. ''' networkIo: list = [0,0,0,0] cache_timeout: int = 86400 try: networkIo = psutil.net_io_counters()[:4] except: pass otime = cache.get("otime") if not otime: otime = time.time() cache.set('up',networkIo[0],cache_timeout) cache.set('down',networkIo[1],cache_timeout) cache.set('otime',otime ,cache_timeout) ntime = time.time() networkInfo: dict = {'up': 0, 'down': 0} networkInfo['upTotal'] = networkIo[0] networkInfo['downTotal'] = networkIo[1] try: networkInfo['up'] = round( float(networkIo[0] - cache.get("up")) / 1024 / (ntime - otime), 2 ) networkInfo['down'] = round( float(networkIo[1] - cache.get("down")) / 1024 / (ntime - otime), 2 ) except: pass networkInfo['downPackets'] = networkIo[3] networkInfo['upPackets'] = networkIo[2] cache.set('up',networkIo[0],cache_timeout) cache.set('down',networkIo[1],cache_timeout) cache.set('otime', time.time(),cache_timeout) return networkInfo def GetSystemInfo() -> dict: systemInfo: dict = {} systemInfo['cpu'] = GetCpuInfo() systemInfo['load'] = GetLoadAverage() systemInfo['mem'] = GetMemInfo() systemInfo['disk'] = GetDiskInfo() return systemInfo def GetIoReadWrite() -> Dict[str, int]: ''' 获取系统IO读写 Returns ------- dict DESCRIPTION. ''' ioDisk = psutil.disk_io_counters() ioTotal: dict = {} ioTotal['write'] = GetIoWrite(ioDisk.write_bytes) ioTotal['read'] = GetIoRead(ioDisk.read_bytes) return ioTotal def GetIoWrite(ioWrite: int) -> int: ''' 获取IO写 Parameters ---------- ioWrite : TYPE DESCRIPTION. Returns ------- int DESCRIPTION. ''' diskWrite: int = 0 oldWrite: int = cache.get('io_write') if not oldWrite: cache.set('io_write', ioWrite) return diskWrite; oldTime: float = cache.get('io_time') newTime: float = time.time() if not oldTime: oldTime = newTime ioEnd: int = (ioWrite - oldWrite) timeEnd: float = (time.time() - oldTime) if ioEnd > 0: if timeEnd 0: return int(diskWrite) return 0 def GetIoRead(ioRead): ''' 读取IO读 Parameters ---------- ioRead : TYPE DESCRIPTION. Returns ------- TYPE DESCRIPTION. ''' diskRead: int = 0 oldRead: int = cache.get('io_read') if not oldRead: cache.set('io_read',ioRead) return diskRead; oldTime: float = cache.get('io_time') newTime: float = time.time() if not oldTime: oldTime = newTime ioEnd: int = (ioRead - oldRead) timeEnd: float = (time.time() - oldTime) if ioEnd > 0: if timeEnd 0: return int(diskRead) return 0 def GetRegValue(key: str, subkey: str, value: str) -> Any: ''' 获取系统注册表信息 Parameters ---------- key : str 类型. subkey : str 路径. value : str key. Returns ------- value : Any DESCRIPTION. ''' import winreg key = getattr(winreg, key) handle = winreg.OpenKey(key, subkey) (value, type) = winreg.QueryValueEx(handle, value) return value def GetSystemVersion() -> str: ''' 获取操作系统版本(多平台) Returns ------- str DESCRIPTION. ''' if UNIX: return GetSystemVersionUnix() return GetSystemVersionWindows() def GetSystemVersionWindows() -> str: ''' 获取操作系统版本(windows) Returns ------- str DESCRIPTION. ''' try: import platform bit: str = 'x86'; if 'PROGRAMFILES(X86)' in os.environ: bit = 'x64' def get(key: str): return GetRegValue( "HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", key ) osName = get('ProductName') build = get('CurrentBuildNumber') version: str = '{} (build {}) {} (Py{})'.format( osName, build, bit, platform.python_version()) return version except Exception as ex: log('获取系统版本失败,错误:' + str(ex)) return '未知系统版本.' def GetSystemVersionUnix() -> str: ''' 获取系统版本(unix) Returns ------- str 系统版本. ''' try: version: str = readFile('/etc/redhat-release') if not version: version = readFile( '/etc/issue' ).strip().split("\n")[0].replace('\\n','').replace('\l','').strip() else: version = version.replace( 'release ','' ).replace('Linux','').replace('(Core)','').strip() v = sys.version_info return version + '(Py {}.{}.{})'.format(v.major, v.minor, v.micro) except Exception as err: log('获取系统版本失败,错误:', err) return '未知系统版本.' def GetBootTime() -> dict: ''' 获取当前系统启动时间 Returns ------- dict DESCRIPTION. ''' bootTime: float = psutil.boot_time() return { 'timestamp': bootTime, 'runtime': time.time() - bootTime, 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) } def GetCpuConstants() -> dict: ''' 获取CPU常量信息 Parameters ---------- cpuConstants : CpuConstants DESCRIPTION. Returns ------- dict DESCRIPTION. ''' return cpuConstants.getDict def GetFullSystemData() -> dict: ''' 获取完全的系统信息 Returns ------- dict DESCRIPTION. ''' systemData: dict = { **GetSystemInfo(), 'network': { **GetNetWork() }, 'io': { **GetIoReadWrite() }, 'boot': { **GetBootTime() }, 'time': time.time() } return systemData cpuConstants = CpuConstants() log('systemInfo 模块初始化完毕!') if __name__ == '__main__': log(GetFullSystemData()) log(GetCpuConstants()) log(GetSystemInfo()) log(GetNetWork()) log(GetIoReadWrite()) utils.py

工具函数

''' @author: Pure-Peace @name: 工具函数 @time: 2020年8月17日 @version: 0.1 ''' import datetime import time def log(text: str, *args) -> None: ''' logger,打印日志用,与print用法一致,但会显示时间 Parameters ---------- text : str DESCRIPTION. *args : TYPE DESCRIPTION. Returns ------- None DESCRIPTION. ''' print('[{}] {}'.format(getTime(1), text), *args) def getTime(needFormat: int = 0, formatMS: bool = True) -> [int, str]: ''' 获取当前时间 Parameters ---------- needFormat : int, optional 需要格式化为2020年8月17日 20:01:40这样的字符串?. The default is 0. formatMS : bool, optional 需要精确到毫秒吗?. The default is True. Returns ------- [int, str] DESCRIPTION. ''' if needFormat != 0: return datetime.datetime.now().strftime(f'%Y-%m-%d %H:%M:%S{r".%f" if formatMS else ""}') return int(str(time.time()).split('.')[0]) 运行 虚拟环境

当前提供windows x64下已安装依赖的虚拟环境(python3.8): https://github.com/Pure-Peace/system-info-api/blob/master/venv_windows.zip

在这里插入图片描述

将其解压到项目目录下,运行run.bat即可

非虚拟环境

请手动安装python3解释器,并使用命令安装依赖

pip install -r requirements.txt

然后运行

python main.py 运行后,访问地址 http://localhost:5678

即启动成功

{ "message": "hello", "status": 1 } [初次]运行后等待5-8秒,项目目录下将会出现缓存的json文件

例如

cpuInfo.json memInfo.json ioInfo.json networkInfo.json loadInfo.json

这些文件的内容将会不断更新。

您可以通过下列地址访问这些系统信息的缓存:

http://localhost:5678/cpu_constants http://localhost:5678/cpu_info http://localhost:5678/io_info http://localhost:5678/mem_info http://localhost:5678/network_info http://localhost:5678/load_info 测试socketio

打开python服务端后,用浏览器打开socketio.html

在这里插入图片描述

在网页建立一个socketio对象,连接到服务端 socketio:https://socket.io/#examples

以下是socketio的更新事件(event):

update_cpu update_io update_mem update_net update_load Pure-Peace


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3