LiveKit的agent介绍
概念
LiveKit核心概念:
- Room(房间)
- Participant(参会人)
- Track(信息流追踪)
Agent 架构图
订阅信息流
agent交互流程
客户端操作
加入房间
房间创建方式
手动
赋予用户创建房间的权限,在客户的加入并创建房间。
自动
客户的指定ws_url和token,加入指定房间。
room = LiveKit.create(appContext = applicationContext)
room.connect(wsUrl, token)
离开房间
调用 Room.disconnect()
通知 LiveKit 离开事件。如果应用程序在未通知 LiveKit 的情况下关闭,则将继续显示参与者在 Room 中 15 秒。
Swift上,当应用程序退出时,会自动调用 Room.disconnect
。
发送消息
发送方式
客户端通过LocalParticipant.publishData
API 向房间中的任何参与者发布任意数据消息。房间数据通过 WebRTC 数据通道发布到SFU;LiveKit 服务器会将该数据转发给聊天室中的一个或多个参与者。
给指定用户发消息,通过设置destinationIdentities
,它表示用户的身份。
// 发送消息
coroutineScope.launch {val data: ByteArray = //...// 发送有损消息给全员,LOSSY表示数据发送一次,无顺序保证。这对于优先考虑交付速度的实时更新来说是理想的选择。room.localParticipant.publishData(data, DataPublishReliability.LOSSY)// 发送可靠的消息给指定成员,RELIABLE表示发送数据时最多重试3次并保证顺序。适合优先保证交付而不是抵延迟的场景,例如室内聊天。val identities = listOf(Participant.Identity("alice"),Participant.Identity("bob"),)room.localParticipant.publishData(data, DataPublishReliability.RELIABLE, identities)
}// 处理接收到的消息
coroutineScope.launch {room.events.collect { event ->if(event is RoomEvent.DataReceived) {// Process data}}
}
消息大小限制
由于 SCTP 协议的限制,对大于 16 KiB 的消息使用数据通道是不切实际的,包括 LiveKit 的协议包装器。我们建议将消息大小保持在 15 KiB 以下。详细了解数据通道大小限制。
消息的topic
消息可以指定topic,在接收方通过topic进行过滤出感兴趣的消息。
发送信息流
livekit默认支持摄像头、麦克风、录屏3个流,也支持用户发布自定义流的配置。
音视频流
// Turns camera track on
room.localParticipant.setCameraEnabled(true)// Turns microphone track on
room.localParticipant.setMicrophoneEnabled(true)
录屏流
// Create an intent launcher for screen capture
// This *must* be registered prior to onCreate(), ideally as an instance val
val screenCaptureIntentLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()
) { result ->val resultCode = result.resultCodeval data = result.dataif (resultCode != Activity.RESULT_OK || data == null) {return@registerForActivityResult}lifecycleScope.launch {room.localParticipant.setScreenShareEnabled(true, data)}
}// When it's time to enable the screen share, perform the following
val mediaProjectionManager =getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
screenCaptureIntentLauncher.launch(mediaProjectionManager.createScreenCaptureIntent())
自定义流配置
// Option 1: set room defaults
val options = RoomOptions(audioTrackCaptureDefaults = LocalAudioTrackOptions(noiseSuppression = true,echoCancellation = true,autoGainControl = true,highPassFilter = true,typingNoiseDetection = true,),videoTrackCaptureDefaults = LocalVideoTrackOptions(deviceId = "",position = CameraPosition.FRONT,captureParams = VideoPreset169.H1080.capture,),audioTrackPublishDefaults = AudioTrackPublishDefaults(audioBitrate = 20_000,dtx = true,),videoTrackPublishDefaults = VideoTrackPublishDefaults(videoEncoding = VideoPreset169.H1080.encoding,)
)
var room = LiveKit.create(...roomOptions = options,
)// Option 2: create tracks manually
val localParticipant = room.localParticipant
val audioTrack = localParticipant.createAudioTrack("audio")
localParticipant.publishAudioTrack(audioTrack)val videoTrack = localParticipant.createVideoTrack("video", LocalVideoTrackOptions(CameraPosition.FRONT,VideoPreset169.H1080.capture
))
localParticipant.publishVideoTrack(videoTrack)
订阅信息流
默认用户进入房间,会监听所有信息流。
coroutineScope.launch {room.events.collect { event ->when(event) {is RoomEvent.TrackSubscribed -> {// Audio tracks are automatically played.val videoTrack = event.track as? VideoTrack ?: return@collectvideoTrack.addRenderer(videoRenderer)}else -> {}}}
}
监听事件
事件分为:room事件和参与者事件。这是事件列表:
EVENT | DESCRIPTION | ROOM EVENT | PARTICIPANT EVENT |
ParticipantConnected 参与者Connected | A RemoteParticipant joins after the local participant. | ✔️ | |
RemoteParticipant 在本地参与者之后加入。 | |||
ParticipantDisconnected 参与者断开连接 | A RemoteParticipant leaves | ✔️ | |
RemoteParticipant 离开 | |||
Reconnecting 重新连接 | The connection to the server has been interrupted and it's attempting to reconnect. | ✔️ | |
与服务器的连接已中断,它正在尝试重新连接。 | |||
Reconnected 重新 | Reconnection has been successful | ✔️ | |
重新连接成功 | |||
Disconnected 断开 | Disconnected from room due to the room closing or unrecoverable failure | ✔️ | |
由于会议室关闭或无法恢复的故障而与会议室断开连接 | |||
TrackPublished 轨迹已发布 | A new track is published to room after the local participant has joined | ✔️ | ✔️ |
本地参加者加入后,新轨道将发布到聊天室 | |||
TrackUnpublished TrackUnpublished (未发布) | A RemoteParticipant has unpublished a track | ✔️ | ✔️ |
RemoteParticipant 已取消发布轨道 | |||
TrackSubscribed | The LocalParticipant has subscribed to a track | ✔️ | ✔️ |
LocalParticipant 已订阅跟踪 | |||
TrackUnsubscribed 跟踪Unsubscribed | A previously subscribed track has been unsubscribed | ✔️ | ✔️ |
之前订阅的曲目已取消订阅 | |||
TrackMuted TrackMuted (轨道静音) | A track was muted, fires for both local tracks and remote tracks | ✔️ | ✔️ |
轨道已静音,本地轨道和远程轨道均触发 | |||
TrackUnmuted TrackUnmuted (轨道未静音) | A track was unmuted, fires for both local tracks and remote tracks | ✔️ | ✔️ |
轨道已取消静音,本地轨道和远程轨道均触发 | |||
LocalTrackPublished LocalTrack已发布 | A local track was published successfully | ✔️ | ✔️ |
已成功发布本地轨道 | |||
LocalTrackUnpublished | A local track was unpublished | ✔️ | ✔️ |
本地曲目未发布 | |||
ActiveSpeakersChanged ActiveSpeakers已更改 | Current active speakers has changed | ✔️ | |
当前当前活跃的发言人已更改 | |||
IsSpeakingChanged | The current participant has changed speaking status | ✔️ | |
当前参与者已更改发言状态 | |||
ConnectionQualityChanged 连接质量已更改 | Connection quality was changed for a Participant | ✔️ | ✔️ |
参与者的连接质量已更改 | |||
ParticipantMetadataChanged | A participant's metadata was updated via server API | ✔️ | ✔️ |
参与者的元数据已通过服务器 API 更新 | |||
RoomMetadataChanged RoomMetadataChanged 的 | Metadata associated with the room has changed | ✔️ | |
与聊天室关联的元数据已更改 | |||
DataReceived 已接收数据 | Data received from another participant or server | ✔️ | ✔️ |
从其他参与者或服务器接收的数据 | |||
TrackStreamStateChanged TrackStreamStateChanged (已更改) | Indicates if a subscribed track has been paused due to bandwidth | ✔️ | ✔️ |
指示订阅的曲目是否因带宽而暂停 | |||
TrackSubscriptionPermissionChanged | One of subscribed tracks have changed track-level permissions for the current participant | ✔️ | ✔️ |
其中一个已订阅的轨道已更改当前参与者的轨道级别权限 | |||
ParticipantPermissionsChanged | When the current participant's permissions have changed | ✔️ | ✔️ |
ParticipantPermissions已更改 | 当前参与者的权限发生更改时 |
服务端操作
生成用户token
需要LiveKit服务的API_KEY和API-SECRET,通过LiveKit API生成JWT令牌。
通过登录JWT获取到用户的信息,identify=user_id+场景,name=用户昵称(默认值),room名称=场景名(user_id)
# server.py
import os
from livekit import api
from flask import Flaskapp = Flask(__name__)@app.route('/getToken')
def getToken():token = api.AccessToken(os.getenv('LIVEKIT_API_KEY'), os.getenv('LIVEKIT_API_SECRET')) \.with_identity("identity") \.with_name("my name") \.with_grants(api.VideoGrants(room_join=True,room="my-room",))return token.to_jwt()
开发环境可以通过CLI快速创建token:
livekit-cli token create --api-key devkey --api-secret secret --join --room test_room --identity test_user --valid-for 24h
token属性
基于JWT的令牌,包含用户身份、放假名称、功能、权限等。按照场景颁发token,也就是对应的房间。
聊天室权限在解码的加入令牌的 video
字段中指定。它可能包含以下一个或多个属性:
FIELD | TYPE | DESCRIPTION |
roomCreate room创建 | bool | Permission to create or delete rooms |
创建或删除聊天室的权限 | ||
roomList roomList 会议室 | bool | Permission to list available rooms |
列出可用会议室的权限 | ||
roomJoin room加入 | bool | Permission to join a room |
加入聊天室的权限 | ||
roomAdmin roomAdmin 管理员 | bool | Permission to moderate a room |
管理聊天室的权限 | ||
roomRecord roomRecord (房间记录) | bool | Permissions to use Egress service |
使用 Egress 服务的权限 | ||
ingressAdmin 入口管理员 | bool 布尔 | Permissions to use Ingress service |
Ingress 服务使用权限 | ||
room 房间 | string 字符串 | Name of the room, required if join or admin is set |
聊天室的名称,如果设置了 join 或 admin,则为必填项 | ||
canPublish 可以发布 | bool 布尔 | Allow participant to publish tracks |
允许参与者发布轨迹 | ||
canPublishData | bool 布尔 | Allow participant to publish data to the room |
允许参与者将数据发布到聊天室 | ||
canPublishSources | string[] 字符串[] | When set, only listed source can be published. (camera, microphone, screen_share, screen_share_audio) |
设置后,只能发布列出的源。(摄像头、麦克风、screen_share、screen_share_audio) | ||
canSubscribe canSubscribe 订阅 | bool 布尔 | Allow participant to subscribe to tracks |
允许参加者订阅曲目 | ||
canUpdateOwnMetadata | bool 布尔 | Allow participant to update its own metadata |
允许参与者更新自己的元数据 | ||
hidden 隐藏 | bool 布尔 | Hide participant from others in the room |
对聊天室中的其他人隐藏参与者 | ||
kind 类 | string 字符串 | Type of participant (standard, ingress, egress, sip, or agent). this field is typically set by LiveKit internals. |
参与者类型(标准、入口、出口、SIP 或代理)。此字段通常由 LiveKit 内部设置。 |
session断开操作
用户离开房间后,回话会结束,通过add_shutdown_callback回调,可以处理后续操作。例如:发送聊天结束事件。
async def entrypoint(ctx: JobContext):async def my_shutdown_hook():# save user state...ctx.add_shutdown_callback(my_shutdown_hook)
Agent操作
创建Agent服务节点
LiveKit的Agent框架现在只支持python的SDK,文档地址如下:https://docs.livekit.io/agents/quickstart/
这是官方给的demo:
import asynciofrom livekit.agents import AutoSubscribe, JobContext, WorkerOptions, cli, llm
from livekit.agents.voice_assistant import VoiceAssistant
from livekit.plugins import deepgram, openai, silero# This function is the entrypoint for the agent.
async def entrypoint(ctx: JobContext):# Create an initial chat context with a system promptinitial_ctx = llm.ChatContext().append(role="system",text=("You are a voice assistant created by LiveKit. Your interface with users will be voice. ""You should use short and concise responses, and avoiding usage of unpronouncable punctuation."),)# Connect to the LiveKit room# indicating that the agent will only subscribe to audio tracksawait ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)# VoiceAssistant is a class that creates a full conversational AI agent.# See https://github.com/livekit/agents/tree/main/livekit-agents/livekit/agents/voice_assistant# for details on how it works.assistant = VoiceAssistant(vad=silero.VAD.load(),stt=deepgram.STT(),llm=openai.LLM(),tts=openai.TTS(),chat_ctx=initial_ctx,)# Start the voice assistant with the LiveKit roomassistant.start(ctx.room)await asyncio.sleep(1)# Greets the user with an initial messageawait assistant.say("Hey, how can I help you today?", allow_interruptions=True)if __name__ == "__main__":# Initialize the worker with the entrypointcli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
Agent的生命周期
- 当worker程序启动时,会通过websocket连接到LiveKit服务器,将自己注册成worker。一个worker下会有多个子进程(Agent)来处理请求。
- 当用户进入房间时,LiveKit服务器通过负载均衡选择一个worker,为用户提供服务。
- 子进程处理来自用户的消息,并给出回复。
- 当用户退出房间时,房间滚啊比,并且断开与agent的连接。
Agent内部执行流程
agent在处理请求时,包含几个节点:
- request handler:判断能否处理请求,不能请求则LiveKit会讲任务交给其他worker
- entrypoint:agent进入房间之前,执行的初始化操作
- prewarm function:agent进程启动时调用,可以执行加载模型等耗时的操作
Worker类型
opts = WorkerOptions(...# when omitted, the default is JobType.JT_ROOMworker_type=JobType.JT_ROOM,
)
JobType 枚举有两个选项:
- JT_ROOM:将为每个房间创建一个新的代理实例。
- JT_PUBLISHER:将为房间里的每个参与者创建一个新的代理实例。
Agent处理请求
处理音频流
@ctx.room.on("track_subscribed")
def on_track_subscribed(track: rtc.Track,publication: rtc.TrackPublication,participant: rtc.RemoteParticipant,
):# 监听音频流if track.kind == rtc.TrackKind.KIND_AUDIO:audio_stream = rtc.AudioStream(track)async for event in audio_stream:do_something(event.frame)
发布音频流
发布音频涉及将流拆分为长度固定的音频帧。内部缓冲区保存 50 毫秒长的音频队列,实时发送。用于发送新帧的 capture_frame 方法是阻塞的,在缓冲区接收整个帧之前阻塞在那里。这样可以更轻松地处理中断。
为了发布音轨,需要事先确定采样率和声道数,以及每帧的长度(样本数)。下面的示例是在 10ms 长帧中以 48kHz 传输恒定的 16 位正弦波:
SAMPLE_RATE = 48000
NUM_CHANNELS = 1 # mono audio
AMPLITUDE = 2 ** 8 - 1
SAMPLES_PER_CHANNEL = 480 # 10ms at 48kHzasync def entrypoint(ctx: JobContext):await ctx.connect()source = rtc.AudioSource(SAMPLE_RATE, NUM_CHANNELS)track = rtc.LocalAudioTrack.create_audio_track("example-track", source)# since the agent is a participant, our audio I/O is its "microphone"options = rtc.TrackPublishOptions(source=rtc.TrackSource.SOURCE_MICROPHONE)# ctx.agent is an alias for ctx.room.local_participantpublication = await ctx.agent.publish_track(track, options)frequency = 440async def _sinewave():audio_frame = rtc.AudioFrame.create(SAMPLE_RATE, NUM_CHANNELS, SAMPLES_PER_CHANNEL)audio_data = np.frombuffer(audio_frame.data, dtype=np.int16)time = np.arange(SAMPLES_PER_CHANNEL) / SAMPLE_RATEtotal_samples = 0while True:time = (total_samples + np.arange(SAMPLES_PER_CHANNEL)) / SAMPLE_RATEsinewave = (AMPLITUDE * np.sin(2 * np.pi * frequency * time)).astype(np.int16)np.copyto(audio_data, sinewave)# send this frame to the trackawait source.capture_frame(frame)total_samples += samples_per_channel
处理文本消息
监听data_received事件,处理用户发来的消息;通过publish_data()发送消息给用户。
@room.on("data_received")
def on_data_received(data: rtc.DataPacket):logging.info("received data from %s: %s", data.participant.identity, data.data)# string payload will be encoded to bytes with UTF-8
await room.local_participant.publish_data("my payload",reliable=True,destination_identities=["identity1", "identity2"],topic="topic1")
相关文章:

LiveKit的agent介绍
概念 LiveKit核心概念: Room(房间)Participant(参会人)Track(信息流追踪) Agent 架构图 订阅信息流 agent交互流程 客户端操作 加入房间 房间创建方式 手动 赋予用户创建房间的…...
青龙面板 升级 及其 依赖更新修复 检测and日志删除等
青龙版本升级 先关闭服务 cd qinglong目录 docker-compose down 关闭 docker pull whyour/qinglong:版本号 //版本号自行选择,如果是为了修复错误,建议版本微升,不然就直接latest 启动 docker-compose up -d 进入容器࿰…...
坐牢第三十七天(Qt)
作业: 使用qt做一个闹钟 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPixmap> #include <QBitmap> #include <QLabel> //标签类 #include <QLineEdit> //行编辑器类 #include <QPushBu…...

Vidu 全球首发「主体参照」新功能,一键同步角色特征;GPT-4o 实时音频项目负责人离职创业丨 RTE 开发者日报
开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「…...

电子地图的主要功能与应用
电子地图,即数字地图,是利用计算机技术,以数字方式存储和查阅的地图。它不仅继承了传统纸质地图的基本功能,还通过现代科技手段实现了诸多创新应用。以下是电子地图的主要功能与应用: 一、主要功能 快速存取与显示&…...

基于Java+SpringBoot+Vue+MySQL的西安旅游管理系统网站
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的西安旅游管理系统网站【附源码文档】、…...
简单介绍 NVIDIA推出的图形处理单元(GPU)架构“安培架构“
概念 "安培架构"(Ampere Architecture)是 NVIDIA 推出的一款图形处理单元(GPU)架构,它是继图灵架构之后的下一代产品。安培架构最初在2020年发布,以其高性能和高效率而闻名,广泛应用…...
Qiskit:量子计算的Python工具包
Qiskit是由IBM开发的开源量子计算软件开发工具包,它提供了一套完整的工具,用于量子电路的设计、模拟、优化和执行。Qiskit支持量子算法的开发,并且可以与IBM的量子计算机硬件进行交互。 Qiskit的主要特点 量子电路设计:Qiskit允…...
Python——贪吃蛇
以下是一个简单的贪吃蛇游戏的Python代码示例: import pygame import time import random# 初始化 Pygame pygame.init()# 定义颜色 BLACK (0, 0, 0) WHITE (255, 255, 255) RED (255, 0, 0) GREEN (0, 255, 0) BLUE (0, 0, 255)# 设置屏幕尺寸 screen_width …...
WPF 依赖属性与附加属性(面试长问)
在WPF中,**依赖属性(Dependency Property)和附加属性(Attached Property)**是WPF依赖属性系统的重要组成部分。它们虽然都基于依赖属性系统,但用途、定义方式和使用场景有显著差异。以下是两者的详细解释及…...
Python 中的各括号用法
括号的使用 在Python中,括号和中括号有不同的用途: 圆括号 (): 函数调用:当你调用一个函数时,需要使用圆括号,即使没有参数。print("Hello, World!") # 调用print函数表达式分组:在…...

业务流程建模(BPM)的重要性及其应用
什么是业务流程建模(BPM)? 业务流程建模(BPM)是对企业内各项业务流程进行图形化描述的一种方法。它旨在通过可视化的方式帮助企业理解和分析现有的业务流程,从而发现潜在的问题并进行改进。BPM通常采用流程…...

isxdigit函数讲解 <ctype.h>头文件函数
目录 1.头文件 2.isxdigit函数使用 方源一把抓住VS2022,顷刻 炼化! 1.头文件 以上函数都需要包括头文件<ctype.h> ,其中包括 isxdigit 函数 #include<ctype.h> 2.isxdigit函数使用 isxdigit 函数是判断字符是否为十六进制数…...
Linux中安装NextCloud
切换为 root 账号 Ubutu 系统默认登录的用户为非 root 权限用户,为了能正常安装 nextCloud,需要切换为 root 账号。执行如下命令即可: sudo su 更新及安装基础包 请依次运行如下命令,有遇到询问的Is this ok [y/d/N]的时候直接键…...
【编程基础知识】什么是数据库事务
事务(Transaction)是数据库管理系统中的一个基本概念,用于确保数据库操作的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability…...

移植案例与原理 - XTS子系统之应用兼容性测试用例开发
往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 startup子系统之syspara_lite系统属性部件 (1) startup子系统之syspara_lite系统属性部件 (2) startup子系…...
关于linux里的df命令以及inode、数据块-stat链接数以及关于awk文本处理命令中内置函数sub、gsub、sprintf
一、关于linux里的df命令以及inode、数据块-stat链接数 Linux中df命令用于显示目前在Linux系统上的文件系统的磁盘使用情况统计,平常这个命令也用得很多,但一般就是使用df -h查看各个分区的空间使用情况,除此外也可以使用df查看当前linux系统…...

如何本地搭建Whisper语音识别模型
要在本地搭建Whisper语音识别模型,您需要以下几个步骤: 步骤一:系统准备 操作系统: 建议使用Ubuntu 20.04或以上版本,确保系统足够稳定和兼容。硬件配置: 最好有一个强大的GPU,因为语音识别涉及大量的计算工作。推荐…...
微信小程序仿微信聊天界面
界面结构: 消息列表: 使用 scroll-view 实现滚动,每条消息使用 view 组件包裹,根据消息类型 (文本、图片、文件) 显示不同内容。输入框区域: 包含输入框 (textarea)、发送按钮 (button) 和上传文件按钮 (view 组件模拟)。头像: 使用 image 组件展示。 …...

文件用电脑生成的在线技巧,能够轻松将多种类型文件转二维码
现在为了能够更加快捷将文件分享给其他人查看,很多人会通过制作二维码的方式来存储文件,这样可以减少文件对内存的占用,而且用户扫码获取内容也更加的方便快捷。二维码能够随时更新内容,可以长期通过一个二维码来提供个不同的内容…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...