当前位置: 首页 > news >正文

kamailio-ACC_JSON模块详解【后端语言go】

要确认 ACC_JSON 模块是否已经成功将计费信息推送到消息队列(MQueue),以及如何从队列中取值,可以按照以下步骤进行操作:


1. 确认 ACC_JSON 已推送到队列

1.1 配置 ACC_JSON

确保 ACC_JSON 模块已正确配置并启用。以下是一个示例配置:

loadmodule "acc_json.so"
modparam("acc_json", "log_flag", 1)  # 启用 JSON 记录
modparam("acc_json", "log_extra", "ua=$hdr(User-Agent);uuid=$avp(i:123)")  # 记录额外信息route {if (method == "INVITE") {setflag(1);  # 设置计费标志t_relay();   # 转发请求}
}
1.2 检查 Kamailio 日志
  • 启动 Kamailio 并观察日志输出。
  • 如果 ACC_JSON 模块成功将数据推送到队列,日志中会显示类似以下内容:
    INFO: acc_json: JSON accounting data pushed to MQueue
    
1.3 检查消息队列
  • ACC_JSON 模块使用 Kamailio 的消息队列(MQueue)来存储 JSON 数据。
  • 默认情况下,消息队列的数据会存储在 Kamailio 的共享内存中。
  • 你可以使用 Kamailio 的 MI(Management Interface)RPC(Remote Procedure Call) 命令来检查队列状态。

2. 从队列中取值

2.1 使用 MI 命令

Kamailio 提供了 MI 命令来管理消息队列。以下是一些常用的 MI 命令:

2.1.1 检查队列状态
kamcmd mq.stats
  • 输出示例:
    {"queues": {"acc_json_queue": {"size": 10,          # 队列中当前的消息数量"max_size": 1000,    # 队列的最大容量"dropped": 0         # 丢弃的消息数量}}
    }
    
2.1.2 从队列中读取消息
kamcmd mq.read acc_json_queue
  • 输出示例:
    {"messages": [{"method": "INVITE","from_tag": "abc123","to_tag": "xyz456","callid": "12345","sip_code": "200","sip_reason": "OK","time": "2025-02-01 12:34:56","ua": "SomeUserAgent/1.0","uuid": "12345"},...]
    }
    
2.2 使用 RPC 命令

Kamailio 也支持通过 RPC 命令管理消息队列。以下是一些常用的 RPC 命令:

2.2.1 检查队列状态
kamctl rpc mq.stats
  • 输出示例:
    {"queues": {"acc_json_queue": {"size": 10,"max_size": 1000,"dropped": 0}}
    }
    
2.2.2 从队列中读取消息
kamctl rpc mq.read acc_json_queue
  • 输出示例:
    {"messages": [{"method": "INVITE","from_tag": "abc123","to_tag": "xyz456","callid": "12345","sip_code": "200","sip_reason": "OK","time": "2025-02-01 12:34:56","ua": "SomeUserAgent/1.0","uuid": "12345"},...]
    }
    

3. 自定义队列处理

如果默认的消息队列功能无法满足需求,可以通过以下方式自定义队列处理:

3.1 使用事件路由

Kamailio 支持通过事件路由(Event Route)处理消息队列中的数据。例如:

event_route[mq:acc_json_queue] {xlog("L_INFO", "Received JSON accounting data: $mqk($mqv)\n");# 在这里处理队列中的数据
}
3.2 编写外部脚本

可以编写外部脚本(如 Python、Shell 脚本)通过 Kamailio 的 MI 或 RPC 接口定期从队列中读取数据,并进行进一步处理。


4. 调试和验证

  • 调试日志:启用 Kamailio 的调试日志,观察 ACC_JSON 模块的行为:
    kamailio -dd -E -e
    
  • 队列监控:使用 MI 或 RPC 命令定期检查队列状态,确保数据被正确推送和读取。

总结

  • 通过 Kamailio 的 MIRPC 命令可以确认 ACC_JSON 是否成功将数据推送到队列,并从队列中读取数据。
  • 如果需要更复杂的处理,可以使用事件路由或编写外部脚本。
  • 确保 Kamailio 配置正确,并定期监控队列状态以避免数据丢失。

要实现 ACC_JSON 模块将计费信息推送到队列,并由 Go 语言从队列中取值并写入数据库,可以按照以下步骤操作:


1. Kamailio 配置

1.1 加载 ACC_JSON 模块

在 Kamailio 配置文件中加载 ACC_JSON 模块,并配置消息队列:

loadmodule "acc_json.so"# 配置 ACC_JSON
modparam("acc_json", "log_flag", 1)  # 启用 JSON 记录
modparam("acc_json", "log_extra", "ua=$hdr(User-Agent);uuid=$avp(i:123)")  # 记录额外信息# 配置消息队列
modparam("mq", "mq_size", 1000)  # 设置队列大小
modparam("mq", "mq_name", "acc_json_queue")  # 设置队列名称route {if (method == "INVITE") {setflag(1);  # 设置计费标志t_relay();   # 转发请求}
}
1.2 验证数据推送

启动 Kamailio 并验证数据是否成功推送到队列:

kamcmd mq.stats
  • 如果队列中有数据,说明 ACC_JSON 模块已成功推送。

2. Go 语言实现

Go 语言程序需要从 Kamailio 的消息队列中读取数据,并将其写入数据库。以下是详细实现思路和代码示例。

2.1 实现思路
  1. 连接 Kamailio:通过 Kamailio 的 RPC 接口连接到消息队列。
  2. 读取队列数据:定期从队列中读取 JSON 格式的计费信息。
  3. 解析 JSON 数据:将读取的 JSON 数据解析为 Go 结构体。
  4. 写入数据库:将解析后的数据写入数据库(如 MySQL、PostgreSQL 等)。
2.2 代码示例
2.2.1 安装依赖

首先,安装 Go 语言的相关依赖:

go get github.com/zero-os/gorpc        # Kamailio RPC 客户端
go get github.com/go-sql-driver/mysql  # MySQL 驱动
2.2.2 Go 代码实现

以下是一个完整的 Go 程序示例:

package mainimport ("database/sql""encoding/json""fmt""log""time""github.com/zero-os/gorpc"_ "github.com/go-sql-driver/mysql"
)// 定义计费信息结构体
type AccountingRecord struct {Method     string `json:"method"`FromTag    string `json:"from_tag"`ToTag      string `json:"to_tag"`CallID     string `json:"callid"`SipCode    string `json:"sip_code"`SipReason  string `json:"sip_reason"`Time       string `json:"time"`UserAgent  string `json:"ua"`UUID       string `json:"uuid"`
}// 数据库配置
const (dbDriver = "mysql"dbUser   = "root"dbPass   = "password"dbName   = "kamailio_acc"
)func main() {// 连接 Kamailio RPCclient := gorpc.NewClient("tcp", "127.0.0.1:2049") // Kamailio RPC 地址defer client.Close()// 连接数据库db, err := sql.Open(dbDriver, fmt.Sprintf("%s:%s@/%s", dbUser, dbPass, dbName))if err != nil {log.Fatalf("Failed to connect to database: %v", err)}defer db.Close()// 定期从队列中读取数据for {// 从队列中读取消息var result map[string]interface{}err := client.Call("mq.read", "acc_json_queue", &result)if err != nil {log.Printf("Failed to read from queue: %v", err)time.Sleep(5 * time.Second) // 等待 5 秒后重试continue}// 解析 JSON 数据messages, ok := result["messages"].([]interface{})if !ok {log.Println("No messages in queue")time.Sleep(5 * time.Second)continue}// 处理每条消息for _, msg := range messages {msgJSON, err := json.Marshal(msg)if err != nil {log.Printf("Failed to marshal message: %v", err)continue}var record AccountingRecordif err := json.Unmarshal(msgJSON, &record); err != nil {log.Printf("Failed to unmarshal message: %v", err)continue}// 将数据写入数据库if err := saveToDatabase(db, record); err != nil {log.Printf("Failed to save record to database: %v", err)}}time.Sleep(1 * time.Second) // 每隔 1 秒检查一次队列}
}// 将数据写入数据库
func saveToDatabase(db *sql.DB, record AccountingRecord) error {query := `INSERT INTO acc_records (method, from_tag, to_tag, callid, sip_code, sip_reason, time, ua, uuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`_, err := db.Exec(query,record.Method,record.FromTag,record.ToTag,record.CallID,record.SipCode,record.SipReason,record.Time,record.UserAgent,record.UUID,)return err
}

3. 数据库表设计

在 MySQL 中创建用于存储计费信息的表:

CREATE TABLE acc_records (id INT AUTO_INCREMENT PRIMARY KEY,method VARCHAR(50) NOT NULL,from_tag VARCHAR(100) NOT NULL,to_tag VARCHAR(100) NOT NULL,callid VARCHAR(100) NOT NULL,sip_code VARCHAR(10) NOT NULL,sip_reason VARCHAR(100) NOT NULL,time DATETIME NOT NULL,ua VARCHAR(255),uuid VARCHAR(100)
);

4. 运行程序

  1. 启动 Kamailio,确保 ACC_JSON 模块正常运行。
  2. 运行 Go 程序:
    go run main.go
    
  3. 程序会定期从 Kamailio 的消息队列中读取数据,并将其写入数据库。

5. 验证结果

  • 检查数据库中的 acc_records 表,确认数据是否成功写入。
  • 观察 Go 程序的日志输出,确保没有错误。

总结

通过以上步骤,可以实现 ACC_JSON 模块将计费信息推送到队列,并由 Go 语言程序从队列中读取数据并写入数据库。这种方法适用于需要将 Kamailio 的计费信息与外部系统集成的场景。

Gin框架代码实际
如果使用 Gin 框架,可以将 Go 程序组织成一个更结构化的 Web 服务,同时保留从 Kamailio 消息队列中读取数据并写入数据库的功能。以下是重新整理的代码示例:


1. 项目结构

kamailio-acc/
├── main.go
├── handlers/
│   └── acc_handler.go
├── models/
│   └── acc_model.go
├── services/
│   └── queue_service.go
├── config/
│   └── config.go
└── go.mod

2. 代码实现

2.1 main.go

主程序入口,初始化 Gin 框架并启动服务。

package mainimport ("kamailio-acc/config""kamailio-acc/handlers""kamailio-acc/services""log""time""github.com/gin-gonic/gin"
)func main() {// 加载配置cfg, err := config.LoadConfig()if err != nil {log.Fatalf("Failed to load config: %v", err)}// 初始化数据库db, err := config.InitDB(cfg)if err != nil {log.Fatalf("Failed to initialize database: %v", err)}// 初始化 Kamailio RPC 客户端client := services.NewKamailioClient(cfg.KamailioRPCAddr)defer client.Close()// 启动队列监听服务go services.StartQueueListener(client, db)// 初始化 Gin 框架r := gin.Default()// 注册路由handlers.RegisterRoutes(r, db)// 启动 Web 服务if err := r.Run(cfg.ServerAddr); err != nil {log.Fatalf("Failed to start server: %v", err)}
}

2.2 config/config.go

配置文件加载和数据库初始化。

package configimport ("database/sql""fmt""log"_ "github.com/go-sql-driver/mysql""github.com/spf13/viper"
)type Config struct {ServerAddr      string `mapstructure:"SERVER_ADDR"`KamailioRPCAddr string `mapstructure:"KAMAILIO_RPC_ADDR"`DBDriver        string `mapstructure:"DB_DRIVER"`DBUser          string `mapstructure:"DB_USER"`DBPassword      string `mapstructure:"DB_PASSWORD"`DBName          string `mapstructure:"DB_NAME"`
}func LoadConfig() (*Config, error) {viper.SetConfigFile(".env")if err := viper.ReadInConfig(); err != nil {return nil, fmt.Errorf("failed to read config file: %v", err)}var cfg Configif err := viper.Unmarshal(&cfg); err != nil {return nil, fmt.Errorf("failed to unmarshal config: %v", err)}return &cfg, nil
}func InitDB(cfg *Config) (*sql.DB, error) {dsn := fmt.Sprintf("%s:%s@/%s", cfg.DBUser, cfg.DBPassword, cfg.DBName)db, err := sql.Open(cfg.DBDriver, dsn)if err != nil {return nil, fmt.Errorf("failed to connect to database: %v", err)}if err := db.Ping(); err != nil {return nil, fmt.Errorf("failed to ping database: %v", err)}log.Println("Connected to database")return db, nil
}

2.3 models/acc_model.go

定义数据模型和数据库操作方法。

package modelsimport ("database/sql""log"
)type AccountingRecord struct {Method    string `json:"method"`FromTag   string `json:"from_tag"`ToTag     string `json:"to_tag"`CallID    string `json:"callid"`SipCode   string `json:"sip_code"`SipReason string `json:"sip_reason"`Time      string `json:"time"`UserAgent string `json:"ua"`UUID      string `json:"uuid"`
}func SaveRecord(db *sql.DB, record AccountingRecord) error {query := `INSERT INTO acc_records (method, from_tag, to_tag, callid, sip_code, sip_reason, time, ua, uuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`_, err := db.Exec(query,record.Method,record.FromTag,record.ToTag,record.CallID,record.SipCode,record.SipReason,record.Time,record.UserAgent,record.UUID,)if err != nil {log.Printf("Failed to save record: %v", err)return err}log.Printf("Saved record: %+v", record)return nil
}

2.4 services/queue_service.go

从 Kamailio 消息队列中读取数据的服务。

package servicesimport ("encoding/json""kamailio-acc/models""log""time""github.com/zero-os/gorpc"
)type KamailioClient struct {client *gorpc.Client
}func NewKamailioClient(addr string) *KamailioClient {return &KamailioClient{client: gorpc.NewClient("tcp", addr),}
}func (kc *KamailioClient) Close() {kc.client.Close()
}func (kc *KamailioClient) ReadQueue(queueName string) ([]models.AccountingRecord, error) {var result map[string]interface{}if err := kc.client.Call("mq.read", queueName, &result); err != nil {return nil, err}messages, ok := result["messages"].([]interface{})if !ok {return nil, nil}var records []models.AccountingRecordfor _, msg := range messages {msgJSON, err := json.Marshal(msg)if err != nil {log.Printf("Failed to marshal message: %v", err)continue}var record models.AccountingRecordif err := json.Unmarshal(msgJSON, &record); err != nil {log.Printf("Failed to unmarshal message: %v", err)continue}records = append(records, record)}return records, nil
}func StartQueueListener(client *KamailioClient, db *sql.DB) {for {records, err := client.ReadQueue("acc_json_queue")if err != nil {log.Printf("Failed to read from queue: %v", err)time.Sleep(5 * time.Second)continue}for _, record := range records {if err := models.SaveRecord(db, record); err != nil {log.Printf("Failed to save record: %v", err)}}time.Sleep(1 * time.Second)}
}

2.5 handlers/acc_handler.go

定义 HTTP 路由和处理程序。

package handlersimport ("database/sql""net/http""github.com/gin-gonic/gin""kamailio-acc/models"
)func RegisterRoutes(r *gin.Engine, db *sql.DB) {r.GET("/records", func(c *gin.Context) {// 示例:从数据库中获取所有记录var records []models.AccountingRecordrows, err := db.Query("SELECT * FROM acc_records")if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}defer rows.Close()for rows.Next() {var record models.AccountingRecordif err := rows.Scan(&record.Method,&record.FromTag,&record.ToTag,&record.CallID,&record.SipCode,&record.SipReason,&record.Time,&record.UserAgent,&record.UUID,); err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}records = append(records, record)}c.JSON(http.StatusOK, records)})
}

3. 配置文件 .env

SERVER_ADDR=:8080
KAMAILIO_RPC_ADDR=127.0.0.1:2049
DB_DRIVER=mysql
DB_USER=root
DB_PASSWORD=password
DB_NAME=kamailio_acc

4. 运行程序

  1. 启动 Kamailio,确保 ACC_JSON 模块正常运行。
  2. 运行 Go 程序:
    go run main.go
    
  3. 访问 http://localhost:8080/records,查看数据库中的计费记录。

总结

通过 Gin 框架,将 Kamailio 的计费信息处理逻辑组织成一个结构化的 Web 服务。Go 程序从 Kamailio 的消息队列中读取数据并写入数据库,同时提供 HTTP 接口供外部系统查询数据。

相关文章:

kamailio-ACC_JSON模块详解【后端语言go】

要确认 ACC_JSON 模块是否已经成功将计费信息推送到消息队列(MQueue),以及如何从队列中取值,可以按照以下步骤进行操作: 1. 确认 ACC_JSON 已推送到队列 1.1 配置 ACC_JSON 确保 ACC_JSON 模块已正确配置并启用。以下…...

ArkTS语言介绍

文章目录 一、基本知识声明类型运算符语句函数函数声明可选参数Rest参数返回类型函数的作用域函数调用函数类型箭头函数(又名Lambda函数)闭包函数重载类字段方法构造函数可见性修饰符对象字面量抽象类接口接口属性接口继承抽象类和接口泛型类型和函数泛型类和接口泛型约束泛型…...

海外问卷调查之渠道查,企业经营的指南针

海外问卷调查,是企业调研最常用到的方法,有目的、有计划、有系统地收集研究对象的现实状况或历史状况的一种有效手段,是指导企业经营的有效手段。 海外问卷调查充分运用历史法、观察法等方法,同时使用谈话、问卷、个案研究、测试…...

spring和Mybatis的逆向工程

在现代企业级开发中,使用Spring和MyBatis进行快速、高效的数据库操作是非常常见的。本文将深入探讨如何使用Spring和MyBatis进行逆向工程,帮助开发者自动生成数据库相关的代码,提高开发效率和代码质量。 一、什么是逆向工程 逆向工程是指从…...

【Android】问deepseek存储访问

这些天deepseek爆火,我们来问问android问题看看,如果问android中的应用怎么访问外部存储,回答的很清楚,但是如果问的深入一些,比如Android中是怎么控制让应用不能读取其他应用的外部存储文件的,回答的比较抽…...

Android记事本App设计开发项目实战教程2025最新版Android Studio

平时上课录了个视频,从新建工程到打包Apk,从头做到尾,没有遗漏任何实现细节,欢迎学过Android基础的同学参加,如果你做过其他终端软件开发,也可以学习,快速上手Android基础开发。 Android记事本课…...

python学习——函数的返回值

在 Python 中,函数的返回值决定了调用该函数后得到的结果。默认情况下,如果函数没有使用 return 语句或没有明确返回一个值,函数将返回 None。为了实现更复杂的逻辑,可以通过 return 语句返回多个值、错误信息或其他数据类型。 返…...

【竞技宝】裂变天地S1:BB0-2PARI淘汰出局

北京时间2月1日,DOTA2裂变天地S1继续进行,昨日共进行三场比赛,第三场比赛迎来败者组第二轮PARI对阵BB。以下是本场比赛的详细战报。 第一局: 首局比赛,BB在天辉方,PARI在夜魇方。阵容方面,BB点出了圣堂、卡尔、玛尔斯、奶绿、亚巴顿,PARI则是拿到小娜迦、凤凰、大圣、玛西、萨…...

数据分析系列--⑨RapidMiner训练集、测试集、验证集划分

一、数据集获取 二、划分数据集 1.导入和加载数据 2.数据集划分 2.1 划分说明 2.2 方法一 2.3 方法二 一、数据集获取 点击下载数据集 此数据集包含538312条数据. 二、划分数据集 1.导入和加载数据 2.数据集划分 2.1 划分说明 2.2 方法一 使用Filter Example Range算子. …...

实践Rust:编写一个猜数字游戏

如果你正在学习Rust,并且想通过一个有趣的小项目来巩固所学知识,那么“猜数字游戏”是一个绝佳的选择!这个游戏的逻辑非常简单:程序会随机生成一个数字,玩家需要猜测这个数字是多少,程序会告诉玩家猜大了还…...

JavaFX - 3D 形状

在前面的章节中,我们已经了解了如何在 JavaFX 应用程序中的 XY 平面上绘制 2D 形状。除了这些 2D 形状之外,我们还可以使用 JavaFX 绘制其他几个 3D 形状。 通常,3D 形状是可以在 XYZ 平面上绘制的几何图形。它们由两个或多个维度定义&#…...

阿里新发的大模型Qwen2.5-max如何?

阿里新发布的大模型Qwen2.5-Max是一款性能卓越、技术先进的大型语言模型,其在多个方面展现了突出的表现。以下是基于我搜索到的资料对Qwen2.5-Max的详细评价: 技术特点 超大规模预训练数据:Qwen2.5-Max采用了超过20万亿tokens的超大规模预训…...

文本复制兼容方案最佳实现落地。

文章目录 一、navigator.clipboard.writeText二、方案落地总结 一、navigator.clipboard.writeText navigator.clipboard.writeText 是一个Web API,它允许网页脚本将文本数据写入用户的系统剪贴板。这个API是异步的,并且设计用于提高安全性和用户体验&a…...

x86-64数据传输指令

关于汇编语言一些基础概念的更详细的介绍,可移步MIPS指令集(一)基本操作_mips指令 sw-CSDN博客 该指令集中一个字2字节。 该架构有16个64位寄存器,名字都以%r开头,每个寄存器的最低位字节,低1~2位字节&…...

LigerUI在MVC模式下的响应原则

LigerUI是基于jQuery的UI框架,故他也是遵守jQuery的开发模式,但是也具有其特色的侦听函数,那么当LigerUI作为View层的时候,他所发送后端的必然是表单的数据,在此我们以俩个div为例: {Layout "~/View…...

java CountDownLatch和CyclicBarrier

专栏系列文章地址:https://blog.csdn.net/qq_26437925/article/details/145290162 本文目标: 理解CountDownLatch和CyclicBarrier的使用,主要是复习Aqs 另外工作中用到CountDownLatch的地方还很多,一般是完成某些事情才能继续某…...

力扣动态规划-17【算法学习day.111】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?建议灵神的题单和代码随想录)和记录自己的学习过程,我的解析也不会做的非常详细,只会提供思路和一些关…...

读书笔记-《你的灯亮着吗?》

这是一本短篇且有趣的书,通过一些小故事讨论了下解决问题时会遇到的困难。 01 为什么难以定义问题 常言道,办法总比问题多,但往往我们在一开始就没有定义好问题: 在学校时,校园教育使得我们会紧紧抓住看起来像是“问题…...

MATLAB实现多种群遗传算法

多种群遗传算法(MPGA, Multi-Population Genetic Algorithm)是一种改进的遗传算法,它通过将种群分成多个子种群并在不同的子种群之间进行交叉和交换,旨在提高全局搜索能力并避免早期收敛。下面是多种群遗传算法的主要步骤和流程&a…...

tf.Keras (tf-1.15)使用记录3-model.compile方法

model.compile 是 TensorFlow Keras 中用于配置训练模型的方法。在开始训练之前,需要通过这个方法来指定模型的优化器、损失函数和评估指标等。 注意事项: 在开始训练(调用 model.fit)之前,必须先调用 model.compile()。 1 基本…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

【机器视觉】单目测距——运动结构恢复

ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛&#xf…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

Win系统权限提升篇UAC绕过DLL劫持未引号路径可控服务全检项目

应用场景: 1、常规某个机器被钓鱼后门攻击后,我们需要做更高权限操作或权限维持等。 2、内网域中某个机器被钓鱼后门攻击后,我们需要对后续内网域做安全测试。 #Win10&11-BypassUAC自动提权-MSF&UACME 为了远程执行目标的exe或者b…...

Netty自定义协议解析

目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...