当前位置: 首页 > 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 基本…...

Prometheus 中的 Exporter

在 Prometheus 生态系统中,Exporter 扮演着至关重要的角色,它们负责从不同的服务或系统中收集和暴露度量数据。本文将详细介绍 Exporter 的概念、类型以及如何有效使用它们将 Prometheus 集成到各种系统中进行监控。 什么是 Exporter? Exporter 是一段软件,它从应用程序或…...

网工_HDLC协议

2025.01.25:网工老姜学习笔记 第9节 HDLC协议 9.1 HDLC高级数据链路控制9.2 HDLC帧格式(*控制字段)9.2.1 信息帧(承载用户数据,0开头)9.2.2 监督帧(帮助信息可靠传输,10开头&#xf…...

leetcode 2563. 统计公平数对的数目

题目如下 数据范围 显然数组长度最大可以到10的5次方n方的复杂度必然超时,阅读题目实际上就是寻找两个位置不同的数满足不等式即可(实际上i j无所谓是哪个 我们只要把位置小的想成i就行)。 按照上面的思路我们只需要排序数组然后从前往后遍历数组然后利用二分查找…...

Debian 10 中 Linux 4.19 内核在 x86_64 架构上对中断嵌套的支持情况

一、中断嵌套的定义与原理 中断嵌套是指在一个中断处理程序(ISR)正在执行的过程中,另一个更高优先级的中断请求到来,系统暂停当前中断处理程序,转而处理新的高优先级中断。处理完高优先级中断后,系统返回到原来的中断处理程序继续执行。这种机制允许系统更高效地响应紧急…...

FLTK - FLTK1.4.1 - demo - bitmap

文章目录 FLTK - FLTK1.4.1 - demo - bitmap概述笔记END FLTK - FLTK1.4.1 - demo - bitmap 概述 // 功能 : 演示位图数据在按钮上的显示 // * 以按钮为范围或者以窗口为范围移动 // * 上下左右, 文字和图像的相对位置 // 失能按钮,使能按钮 // 知识点 // FLTK可…...

数据结构 树1

目录 前言 一,树的引论 二,二叉树 三,二叉树的详细理解 四,二叉搜索树 五,二分法与二叉搜索树的效率 六,二叉搜索树的实现 七,查找最大值和最小值 指针传递 vs 传引用 为什么指针按值传递不会修…...

android主题设置为..DarkActionBar.Bridge时自定义DatePicker选中日期颜色

安卓自定义DatePicker选中日期颜色 背景:解决方案:方案一:方案二:实践效果: 背景: 最近在尝试用原生安卓实现仿element-ui表单校验功能,其中的的选择日期涉及到安卓DatePicker组件的使用&#…...

MySQL 如何深度分页问题

在实际的数据库应用场景中,我们常常会遇到需要进行分页查询的需求。对于少量数据的分页查询,MySQL 可以轻松应对。然而,当我们需要进行深度分页(即从大量数据的中间位置开始获取少量数据)时,就会面临性能严…...

1.攻防世界easyphp

进入题目页面如下 是一段PHP代码进行代码审计 <?php // 高亮显示PHP文件源代码 highlight_file(__FILE__);// 初始化变量$key1和$key2为0 $key1 0; $key2 0;// 从GET请求中获取参数a的值&#xff0c;并赋值给变量$a $a $_GET[a]; // 从GET请求中获取参数b的值&#xff…...

深度学习 Pytorch 神经网络的学习

本节将从梯度下降法向外拓展&#xff0c;介绍更常用的优化算法&#xff0c;实现神经网络的学习和迭代。在本节课结束将完整实现一个神经网络训练的全流程。 对于像神经网络这样的复杂模型&#xff0c;可能会有数百个 w w w的存在&#xff0c;同时如果我们使用的是像交叉熵这样…...