Kamailio-基于Zabbix+Kamcli的SIP指标监控

什么是Kamailio?

Kamailio 是一个开源的 Session Initiation Protocol (SIP) 服务器,它主要用于建立和管理实时通信会话,如语音和视频通话,与opensips这个产品是同根同源的存在。它们相似,没有更好,是有更合适。

此篇文章适用于对Kamailio以及VOIP相关有一定基础知识的人,如需恶补请参考专栏, zero to hero。

为什么要监控?

当我们开始使用Kamailio之后,就会产生一些担忧:

  • 脚本适配性如何
  • 是否有一些意料不到的问题无法知晓
  • UDP信令是否有丢失
  • 服务的资源使用情况如何?

因此监控对于服务来说,是必须的。

对于市面上很多监控、展示的监控软件来看,对SIP类型的监控的支持并不多,今天就介绍一个 51star 的小众github开源项目-Kamcli。

它是一个5人开发的,基于原生Kamctl命令,使用Python实现指令封装工具,主要定期调用原生指令,与zabbix-agent配合,最终将业务监控指标数据展示在Zabbix中。

先讲讲我的评价:

  • 相对短小精悍
  • 用于基础指标监控
  • 是一个可与zabbix配合SIP监控小工具

它的实现逻辑也不算复杂,可以自行观看。

Kamcli

安装

前置条件:

  • python3 (python version 3.x, recommended at least Python 3.7)
  • python3-pip
  • python3-setuptools
  • python3-dev (optional - needed to install mysqlclient via pip)
  • python3-venv (optional - needed to install virtual environment)

关于服务器环境没有太多限制:可以虚拟机、Debian、Ubuntu、Mint、CentOS。区别可能就在于python基础环境安装的步骤有所差异。

安装依赖环境:

$ pip3 install -r requirements/requirements.txt

如果使用MySQL作为后台数据库的话,还需要安装 mysqlclient,这个很好理解。

$ pip3 install mysqlclient

此外后端存储还可以使用 PostgreSQL\SQLite。

拉取代码进行编译安装,我们这边就采用现有的一个MySQL数据库。

$ git clone https://github.com/kamailio/kamcli.git
$ cd kamcli
$ pip3 install -r requirements/requirements.txt
$ pip3 install mysqlclient
$ pip3 install --editable .

完成以上步骤后,环境版本没有冲突报错的话,就可以顺利安装完成:

使用

$ /usr/local/bin/kamcli --help
Usage: kamcli [OPTIONS] COMMAND [ARGS]...Kamailio command line interface control tool.Help per command: kamcli <command> --helpDefault configuration files:- /etc/kamcli/kamcli.ini- ./kamcli.ini- ./kamcli/kamcli.ini- ~/.kamcli/kamctli.iniConfigs loading order: default configs, then --config optionLicense: GPLv2Copyright: asipto.comOptions:-d, --debug                     Enable debug mode.-c, --config TEXT               Configuration file.-w, --wdir DIRECTORY            Working directory.-n, --no-default-configs        Skip loading default configuration files.-F, --output-format [raw|json|table|dict|yaml]Format the output (overwriting db/jsonrpcoutformat config attributes)--version                       Show the version and exit.-h, --help                      Show this message and exit.Commands:acc         Accounting managementaddress     Manage permissions address recordsaliasdb     Manage database user aliasesapiban      Manage APIBan recordsavp         Manage AVP user preferencesconfig      Manage the config filedb          Raw database operationsdialog      Manage dialog moduledialplan    Manage dialplan moduledispatcher  Manage dispatcher moduledlgs        Manage dlgs moduledomain      Manage domain modulegroup       Manage group modulehtable      Management of htable modulejsonrpc     Execute JSONRPC commandsmoni        Monitor relevant statisticsmtree       Manage mtree modulepike        Manage pike moduleping        Send an OPTIONS ping requestpipelimit   Manage pipelimit modulepkg         Private memory (pkg) managementps          Print the list of kamailio processespstrap      Get runtime details and gdb backtrace with psrpcmethods  Print the list of available raw RPC methodsrtpengine   Manage rtpengine moduleshell       Run in interactive shell modeshm         Shared memory (shm) managementshv         Manage $shv(name) variablessipreq      Send a SIP request via RPC commandspeeddial   Manage speed dial recordssrv         Common server interaction commandsstats       Print internal statisticssubscriber  Manage the subscriberstcp         Manage TCP options and connectionstls         Manage tls moduletrap        Get runtime details and gdb full backtraceuacreg      Manage uac registrationsul          Manage user location recordsuptime      Print the uptime for kamailio

样例:

kamcli -d --help
kamcli -d --config=kamcli/kamcli.ini --helpkamcli subscriber show
kamcli subscriber add test test00
kamcli subscriber show test
kamcli subscriber show --help
kamcli -d subscriber passwd test01 test10
kamcli -d subscriber add -t no test02 test02
kamcli -d subscriber setattrs test01 rpid +123
kamcli -d subscriber setattrnull test01 rpidkamcli -d jsonrpc --help
kamcli -d jsonrpc core.psx
kamcli -d jsonrpc system.listMethods
kamcli -d jsonrpc stats.get_statistics
kamcli -d jsonrpc stats.get_statistics all
kamcli -d jsonrpc stats.get_statistics shmem:
kamcli -d jsonrpc --dry-run system.listMethodskamcli -d config raw
kamcli -d config show main db
kamcli -d -no-default-configs config show main dbkamcli -d db connect
kamcli -d db show -F table version
kamcli -d db show -F json subscriber
kamcli -d db showcreate version
kamcli -d db showcreate -F table version
kamcli -d db showcreate -F table -S html version
kamcli -d db clirun "describe version"
kamcli -d db clishow version
kamcli -d db clishowg subscriberkamcli -d ul showdb
kamcli -d ul show
kamcli -d ul rm test
kamcli -d ul add test sip:test@127.0.0.1kamcli -d stats
kamcli -d stats usrloc
kamcli -d stats -s registered_users
kamcli -d stats usrloc:registered_users

看到封装后的指令应该是非常熟悉,都是来自于kamctl命令行,就像它的slogan。

kamcli is aiming at being a modern and extensible alternative to the shell script kamctl.

对于监控统计而言,比较关注的就是 kamcli stats

$ kamcli statsid: 6694
jsonrpc: '2.0'
result:core.bad_URIs_rcvd: '0'core.bad_msg_hdr: '0'core.drop_replies: '0'core.drop_requests: '0'core.err_replies: '0'core.err_requests: '0'core.fwd_replies: '0'core.fwd_requests: '4'core.rcv_replies: '286'core.rcv_replies_18x: '3'core.rcv_replies_1xx: '141'core.rcv_replies_1xx_bye: '0'core.rcv_replies_1xx_cancel: '0'core.rcv_replies_1xx_invite: '141'core.rcv_replies_1xx_message: '0'core.rcv_replies_1xx_prack: '0'core.rcv_replies_1xx_refer: '0'core.rcv_replies_1xx_reg: '0'core.rcv_replies_1xx_update: '0'core.rcv_replies_2xx: '5'core.rcv_replies_2xx_bye: '1'core.rcv_replies_2xx_cancel: '0'core.rcv_replies_2xx_invite: '4'core.rcv_replies_2xx_message: '0'core.rcv_replies_2xx_prack: '0'core.rcv_replies_2xx_refer: '0'core.rcv_replies_2xx_reg: '0'core.rcv_replies_2xx_update: '0'core.rcv_replies_3xx: '0'core.rcv_replies_3xx_bye: '0'core.rcv_replies_3xx_cancel: '0'core.rcv_replies_3xx_invite: '0'core.rcv_replies_3xx_message: '0'core.rcv_replies_3xx_prack: '0'core.rcv_replies_3xx_refer: '0'core.rcv_replies_3xx_reg: '0'core.rcv_replies_3xx_update: '0'core.rcv_replies_401: '0'core.rcv_replies_404: '0'core.rcv_replies_407: '0'core.rcv_replies_480: '0'core.rcv_replies_486: '0'core.rcv_replies_4xx: '140'core.rcv_replies_4xx_bye: '0'core.rcv_replies_4xx_cancel: '0'core.rcv_replies_4xx_invite: '140'core.rcv_replies_4xx_message: '0'core.rcv_replies_4xx_prack: '0'core.rcv_replies_4xx_refer: '0'core.rcv_replies_4xx_reg: '0'core.rcv_replies_4xx_update: '0'core.rcv_replies_5xx: '0'core.rcv_replies_5xx_bye: '0'core.rcv_replies_5xx_cancel: '0'core.rcv_replies_5xx_invite: '0'core.rcv_replies_5xx_message: '0'core.rcv_replies_5xx_prack: '0'core.rcv_replies_5xx_refer: '0'core.rcv_replies_5xx_reg: '0'core.rcv_replies_5xx_update: '0'core.rcv_replies_6xx: '0'core.rcv_replies_6xx_bye: '0'core.rcv_replies_6xx_cancel: '0'core.rcv_replies_6xx_invite: '0'core.rcv_replies_6xx_message: '0'core.rcv_replies_6xx_prack: '0'core.rcv_replies_6xx_refer: '0'core.rcv_replies_6xx_reg: '0'core.rcv_replies_6xx_update: '0'core.rcv_requests: '293'core.rcv_requests_ack: '144'core.rcv_requests_bye: '3'core.rcv_requests_cancel: '0'core.rcv_requests_info: '0'core.rcv_requests_invite: '146'core.rcv_requests_message: '0'core.rcv_requests_notify: '0'core.rcv_requests_options: '0'core.rcv_requests_prack: '0'core.rcv_requests_publish: '0'core.rcv_requests_refer: '0'core.rcv_requests_register: '0'core.rcv_requests_subscribe: '0'core.rcv_requests_update: '0'core.unsupported_methods: '0'dns.failed_dns_request: '0'dns.slow_dns_request: '0'mysql.driver_errors: '0'registrar.accepted_regs: '0'registrar.default_expire: '3600'registrar.default_expires_range: '0'registrar.expires_range: '0'registrar.max_contacts: '0'registrar.max_expires: '3600'registrar.rejected_regs: '0'shmem.fragments: '6'shmem.free_size: '131134656'shmem.max_used_size: '5958976'shmem.real_used_size: '3083072'shmem.total_size: '134217728'shmem.used_size: '2801584'sl.1xx_replies: '0'sl.200_replies: '0'sl.202_replies: '0'sl.2xx_replies: '0'sl.300_replies: '0'sl.301_replies: '0'sl.302_replies: '0'sl.3xx_replies: '0'sl.400_replies: '0'sl.401_replies: '0'sl.403_replies: '0'sl.404_replies: '2'sl.407_replies: '0'sl.408_replies: '0'sl.483_replies: '2'sl.4xx_replies: '0'sl.500_replies: '0'sl.5xx_replies: '0'sl.6xx_replies: '0'sl.failures: '2'sl.received_ACKs: '0'sl.sent_err_replies: '0'sl.sent_replies: '4'sl.xxx_replies: '0'tcp.con_reset: '0'tcp.con_timeout: '0'tcp.connect_failed: '0'tcp.connect_success: '0'tcp.current_opened_connections: '0'tcp.current_write_queue_size: '0'tcp.established: '0'tcp.local_reject: '0'tcp.passive_open: '0'tcp.send_timeout: '0'tcp.sendq_full: '0'tmx.2xx_transactions: '5'tmx.3xx_transactions: '0'tmx.4xx_transactions: '146'tmx.5xx_transactions: '0'tmx.6xx_transactions: '0'tmx.UAC_transactions: '6'tmx.UAS_transactions: '151'tmx.active_transactions: '0'tmx.inuse_transactions: '0'tmx.rpl_absorbed: '138'tmx.rpl_generated: '150'tmx.rpl_received: '286'tmx.rpl_relayed: '148'tmx.rpl_sent: '298'usrloc.location_contacts: '0'usrloc.location_expires: '0'usrloc.location_users: '0'usrloc.registered_users: '0'

对比一下原生的 kamctl:

$ kamctl stats 
{"jsonrpc":  "2.0","result": ["core:bad_URIs_rcvd = 0","core:bad_msg_hdr = 0","core:drop_replies = 0","core:drop_requests = 0","core:err_replies = 0","core:err_requests = 0","core:fwd_replies = 0","core:fwd_requests = 4","core:rcv_replies = 286","core:rcv_replies_18x = 3","core:rcv_replies_1xx = 141","core:rcv_replies_1xx_bye = 0","core:rcv_replies_1xx_cancel = 0","core:rcv_replies_1xx_invite = 141","core:rcv_replies_1xx_message = 0","core:rcv_replies_1xx_prack = 0","core:rcv_replies_1xx_refer = 0","core:rcv_replies_1xx_reg = 0","core:rcv_replies_1xx_update = 0","core:rcv_replies_2xx = 5","core:rcv_replies_2xx_bye = 1","core:rcv_replies_2xx_cancel = 0","core:rcv_replies_2xx_invite = 4","core:rcv_replies_2xx_message = 0","core:rcv_replies_2xx_prack = 0","core:rcv_replies_2xx_refer = 0","core:rcv_replies_2xx_reg = 0","core:rcv_replies_2xx_update = 0","core:rcv_replies_3xx = 0","core:rcv_replies_3xx_bye = 0","core:rcv_replies_3xx_cancel = 0","core:rcv_replies_3xx_invite = 0","core:rcv_replies_3xx_message = 0","core:rcv_replies_3xx_prack = 0","core:rcv_replies_3xx_refer = 0","core:rcv_replies_3xx_reg = 0","core:rcv_replies_3xx_update = 0","core:rcv_replies_401 = 0","core:rcv_replies_404 = 0","core:rcv_replies_407 = 0","core:rcv_replies_480 = 0","core:rcv_replies_486 = 0","core:rcv_replies_4xx = 140","core:rcv_replies_4xx_bye = 0","core:rcv_replies_4xx_cancel = 0","core:rcv_replies_4xx_invite = 140","core:rcv_replies_4xx_message = 0","core:rcv_replies_4xx_prack = 0","core:rcv_replies_4xx_refer = 0","core:rcv_replies_4xx_reg = 0","core:rcv_replies_4xx_update = 0","core:rcv_replies_5xx = 0","core:rcv_replies_5xx_bye = 0","core:rcv_replies_5xx_cancel = 0","core:rcv_replies_5xx_invite = 0","core:rcv_replies_5xx_message = 0","core:rcv_replies_5xx_prack = 0","core:rcv_replies_5xx_refer = 0","core:rcv_replies_5xx_reg = 0","core:rcv_replies_5xx_update = 0","core:rcv_replies_6xx = 0","core:rcv_replies_6xx_bye = 0","core:rcv_replies_6xx_cancel = 0","core:rcv_replies_6xx_invite = 0","core:rcv_replies_6xx_message = 0","core:rcv_replies_6xx_prack = 0","core:rcv_replies_6xx_refer = 0","core:rcv_replies_6xx_reg = 0","core:rcv_replies_6xx_update = 0","core:rcv_requests = 293","core:rcv_requests_ack = 144","core:rcv_requests_bye = 3","core:rcv_requests_cancel = 0","core:rcv_requests_info = 0","core:rcv_requests_invite = 146","core:rcv_requests_message = 0","core:rcv_requests_notify = 0","core:rcv_requests_options = 0","core:rcv_requests_prack = 0","core:rcv_requests_publish = 0","core:rcv_requests_refer = 0","core:rcv_requests_register = 0","core:rcv_requests_subscribe = 0","core:rcv_requests_update = 0","core:unsupported_methods = 0","dns:failed_dns_request = 0","dns:slow_dns_request = 0","mysql:driver_errors = 0","registrar:accepted_regs = 0","registrar:default_expire = 3600","registrar:default_expires_range = 0","registrar:expires_range = 0","registrar:max_contacts = 0","registrar:max_expires = 3600","registrar:rejected_regs = 0","shmem:fragments = 6","shmem:free_size = 131134656","shmem:max_used_size = 5958976","shmem:real_used_size = 3083072","shmem:total_size = 134217728","shmem:used_size = 2801584","sl:1xx_replies = 0","sl:200_replies = 0","sl:202_replies = 0","sl:2xx_replies = 0","sl:300_replies = 0","sl:301_replies = 0","sl:302_replies = 0","sl:3xx_replies = 0","sl:400_replies = 0","sl:401_replies = 0","sl:403_replies = 0","sl:404_replies = 2","sl:407_replies = 0","sl:408_replies = 0","sl:483_replies = 2","sl:4xx_replies = 0","sl:500_replies = 0","sl:5xx_replies = 0","sl:6xx_replies = 0","sl:failures = 2","sl:received_ACKs = 0","sl:sent_err_replies = 0","sl:sent_replies = 4","sl:xxx_replies = 0","tcp:con_reset = 0","tcp:con_timeout = 0","tcp:connect_failed = 0","tcp:connect_success = 0","tcp:current_opened_connections = 0","tcp:current_write_queue_size = 0","tcp:established = 0","tcp:local_reject = 0","tcp:passive_open = 0","tcp:send_timeout = 0","tcp:sendq_full = 0","tmx:2xx_transactions = 5","tmx:3xx_transactions = 0","tmx:4xx_transactions = 146","tmx:5xx_transactions = 0","tmx:6xx_transactions = 0","tmx:UAC_transactions = 6","tmx:UAS_transactions = 151","tmx:active_transactions = 0","tmx:inuse_transactions = 0","tmx:rpl_absorbed = 138","tmx:rpl_generated = 150","tmx:rpl_received = 286","tmx:rpl_relayed = 148","tmx:rpl_sent = 298","usrloc:location_contacts = 0","usrloc:location_expires = 0","usrloc:location_users = 0","usrloc:registered_users = 0"],"id": 22824
}

关于配置文件

配置文件可放置在这些目录下:

  • ./kamcli/kamcli.ini
  • ./kamcli.ini
  • /etc/kamcli/kamcli.ini
  • ~/.kamcli/kamcli.ini

看看配置文件的内容:

### main options
[main]
; SIP domain to be used when an AoR has no domain
domain=kamailio.org### subcommand aliases
[cmdaliases]
# alias = subcommand
# - 'kamcli alias ...' becomes equivalent of 'kamcli subcommand ...'
mt = mtree
pl = pipelimit
sd = speeddial### database connectivity - URLs are used for SQL Alchemy
[db]
; type of database
; - for MySQL: mysql,
; - for PostgreSQL: postgresql
; - for SQLite: sqlite
type=mysql
; driver to be used fro connecting
; - for MySQL: mysqldb
; - for PostgreSQL: psycopg2
; - for SQLite: pysqlite
driver=mysqldb
; host of database server
host=localhost
; port of database server
; - not enforced - see rwurl, rourl, adminurl
; - for MySQL: 3306
; - for PostgreSQL: 5432
dbport=3306
; kamailio database name for SQL server backends
dbname=kamailio
; kamailio database path for SQL file backends (e.g., sqlite)
dbpath=/etc/kamailio/kamailio.db
; read/write user
rwuser=kamailio
; password for read/write user
rwpassword=kamailiorw
; read only user
rouser=kamailioro
; password for read only user
ropassword=kamailioro
; admin user
adminuser=root
; password for admin user
adminpassword=
; database URLs
; - built using above attributes, don't change unless you know what you do
; - full format for SQL server backends (mysql, postgres, ...):
;     rwurl=%(type)s+%(driver)s://%(rwuser)s:%(rwpassword)s@%(host)s:%(dbport)s/%(dbname)s
;     rourl=%(type)s+%(driver)s://%(rouser)s:%(ropassword)s@%(host)s:%(dbport)s/%(dbname)s
;     adminurl=%(type)s+%(driver)s://%(adminuser)s:%(adminpassword)s@%(host)s:%(dbport)s
; - full format for SQL file backends (sqlite, ...):
;     rwurl=%(type)s+%(driver)s:///%(dbpath)s
;     rourl=%(type)s+%(driver)s:///%(dbpath)s
;     adminurl=%(type)s+%(driver)s:///%(dbpath)s
rwurl=%(type)s+%(driver)s://%(rwuser)s:%(rwpassword)s@%(host)s/%(dbname)s
rourl=%(type)s+%(driver)s://%(rouser)s:%(ropassword)s@%(host)s/%(dbname)s
adminurl=%(type)s+%(driver)s://%(adminuser)s:%(adminpassword)s@%(host)s; host from where kamcli is used
accesshost=; path to the folder with SQL scripts for creating database tables
; - used by `db create` subcommand if not provided via `-s` cli argument
; - example value for mysql: /usr/local/share/kamailio/mysql
; - example value for postgresql: /usr/local/share/kamailio/postgres
; - example value for sqlite: /usr/local/share/kamailio/db_sqlite
scriptsdirectory=/usr/local/share/kamailio/mysql; outformat - the format to print database result
; - can be: table, json, yaml, dict or raw
outformat=table; outstyle - the style to print database result with tabulate package
; - default: grid
# outstyle=grid### control tool settings
[ctl]
; type - can be: jsonrpc
type=jsonrpc
; kamgroup - group of the running kamailio server process
kamgroup=kamailio### jsonrpc settings
[jsonrpc]
; transport - can be: fifo, socket
transport=socket; path - where kamailio is listening for JSONRPC FIFO commands
path=/var/run/kamailio/kamailio_rpc.fifo
rplnamebase=kamailio_rpc_reply.fifo
rpldir=/tmp; srvaddr - where kamailio is listening for JSONRPC socket commands
;   - it has to be a path to unix socket file, udp:ipaddr:port
;     or tcp:ipaddr:port
srvaddr=/var/run/kamailio/kamailio_rpc.sock
; srvaddr=udp:127.0.0.1:9062
; srvaddr=tcp:127.0.0.1:9062; rcvaddr - where kamcli is listening for the JSONRPC responses
;   - it has to be a path to unix socket file or udp:ipaddr:port
;   - pid of kamcli is added at the end to allow multiple use at same time
rcvaddr=/var/run/kamailio/kamailio_rpc_reply.sock
; rcvaddr=udp:127.0.0.1:9064; outformat - the format to print RPC result
; - can be: json, yaml or raw
; - yaml is more compact output
outformat=yaml### internal cmd shell settings
[shell]
; do not connect to Kamailio on start up (yes|no)
# noconnect=yes; do not fetch RPC commands on start up for auto-complete (yes|no)
; - done only if 'noconnect=no'
# norpcautocomplete=yes; do not track history of commands (yes|no)
# nohistory=yes; do not enable syntax higlighting for shell command line (yes|no)
# nosyntax=yes### command re-mapping for cmd shell
# - short name for full command with parameters
[shell.cmdremap]
dv=db show "version"
u=uptime### apiban settings
[apiban]
; key - the APIBan key
# key=abcde...; htname - htable name (if not set, defaults to 'ipban')
# htname=ipban

可以采用上面的内容自行新建,也可以通过指令生产默认的文件:

$ kamcli config install
# 文件将位于 /etc/kamcli/kamcli.ini$ kamcli config install -u
# 文件将位于用户目录下 ~/.kamcli/kamcli.ini

结果展示

来看看 Zabbix采集后是什么样?

在这里插入图片描述

数据其实就是命令行可查的那些,通过Zabbix这个平台存储后,能够查看一些关键指标的时间变化趋势,对了解业务情况,发现业务瓶颈有很大帮助.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1534116.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

LLM - 理解 多模态大语言模型 (MLLM) 的指令微调与相关技术 (四)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/142063880 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 完备(F…

获取京东商品详情数据API接口优惠券信息(通过商品id获取商品详情页数据)调用说明文档

在当今数字化时代&#xff0c;应用程序之间的互操作性已成为推动业务创新和技术进步的关键因素。API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;作为这一生态系统中不可或缺的一环&#xff0c;扮演着连接不同软件服务、数据资源和…

AE 让合成重复循环播放

在合成上点右键 > Time > Enable Time Remapping 按住 Alt 键&#xff0c;点秒表图标 输入 loop_out("cycle", 0) 将子合成拖到此合成结束的位置 结束

Ton的编译过程(上)

系列文章目录 FunC编写初始准备 文章目录 系列文章目录预先准备第一个FunC合约深入compileFunc的内部compileFunc初探艾丽卡的疑惑package.json 初览index.js 预先准备 首先请大家跟着艾丽卡一步一步的完成FunC编写初始准备 这里面环境的搭建。 接下来&#xff0c;请做好下面…

通过python提取PDF文件指定页的图片

整体思路 要从 PDF 文件中提取指定页和指定位置的图片&#xff0c;可以分几个步骤来实现&#xff1a; 1.1 准备所需工具与库 在 Python 中处理 PDF 和图像时&#xff0c;需要使用几个库&#xff1a; PyMuPDF (fitz)&#xff1a;用于读取和处理 PDF 文件&#xff0c;可以精确…

Android 测试机

要测手机应用&#xff0c;直接挂电脑上跑虚拟机的话&#xff0c;怀疑电脑都要起火了。 eBay 上买了个新的机器&#xff0c;也才 100 美元多点&#xff0c;机器都没有拆过&#xff0c;电池是完全无电的状态。 操作系统是 Android 12 的版本&#xff0c;升级到 Android 14 后&am…

表格标记<table>

一.表格标记、 1table&#xff1a;表格标记 2.caption:表单标题标记 3.tr:表格行标记 4.td:表格中数据单元格标记 5.th:标题单元格 table标记是表格中最外层标记&#xff0c;tr表示表格中的行标记&#xff0c;一对<tr>表示表格中的一行&#xff0c;在<tr>中可…

Spring Boot集成Akka Stream快速入门Demo

1.什么是Akka Stream&#xff1f; Akka Streams是一个用于处理和传输元素序列的库。它建立在Akka Actors之上&#xff0c;使流的摄入和处理变得简单。由于它是建立在Akka Actors之上的&#xff0c;它为Akka现有的actor模型提供了一个更高层次的抽象。Akka流由3个主要部分组成-…

Linux 入门:简单的基础操作

“批判他人总是想的太简单 剖析自己总是想的太困难” 文章目录 前言Linux 入门&#xff1a;从基础操作到 WSL2 安装文章有误敬请斧正 不胜感恩&#xff01;1. 什么是 Linux&#xff1f;2. Linux 和其他系统有啥不同&#xff1f;3. Linux 的主要组成4. 常见 Linux 发行版5. 基本…

DNS查询报文分析

目录 1. 用 tcpdump工具监听抓包 2. 用 host 工具获取域名对应的IP地址 3. 分析DNS以太网查询数据帧 3.1 linux下查询DNS服务器IP地址 3.2 DNS以太网查询数据帧 &#xff08;1&#xff09;数据链路层 &#xff08;2&#xff09;网络层 &#xff08;3&#xff09;传输层…

【C++】—— list 的了解与使用

【C】—— list 的了解与使用 1 list 的函数接口2 迭代器2.1 简单使用 list 的迭代器2.2 迭代器的划分2.3 不同迭代器的使用场景2.3.1 sort2.3.2 reverse2.3.3 find 3 emplace_back4 操作函数4.1 sort4.1.1 list中sort介绍4.1.2 list 中 sort 与算法库中 sort 效率比较 4.2 mer…

Web:HTTP包的相关操作

目录 一、请求包修改页面来源 二、Cookie身份认证 三、XXF修改本地访问 四、向页面同时发出GET和POST请求 一、请求包修改页面来源 题目提示要从 http://localhost:8080/flag3cad.php?a1&#xff0c;请求包中没有指定请求来源&#xff0c;需要指定。 而表示页面来源的字段…

华南医电科技集团受邀出席中马建交50周年高级别经贸合作交流活动

左:马来西亚第九任首拿督斯里 伊斯迈尔沙必里雅各布; 右:华南医电董事长陈广元 在庆祝中国和马来西亚建交50周年的辉煌时刻,中马两国间的经贸合作不仅承载着历史的重任,更展望着未来无限的广阔前景。2024年,作为这一重要里程碑的纪念之年,中马两国政府及商界精英携手举办了一…

解决项目启动时报“找不到符号”问题

前言 在Java开发过程中&#xff0c;遇到“找不到符号”的错误是非常常见的现象。这种错误往往意味着编译器无法识别你所引用的某个类、方法或变量。本文旨在提供一套详细的排查和解决思路&#xff0c;帮助开发者快速定位并解决此类问题。 问题描述 “找不到符号”错误通常出…

Ubuntu下安装最新版本Apache2文件服务器

文章目录 1.最新版本Apache2安装2. Apache2配置2.1 端口配置2.2 创建软连接,生成文件服务2.3 隐藏Apache2服务版本号2.4 添加用户&#xff0c;设置Apache2文件服务密码2.5 重启Apache2服务3. 执行后效果 1.最新版本Apache2安装 注意&#xff1a;安装最新版本必须升级Ubuntu为20…

网络药理学:15、草稿暂存区

TCMSP 韦恩图在线网站 https://bioinfogp.cnb.csic.es/tools/venny/index.html String数据库参数详解&#xff1a;https://www.bilibili.com/video/BV1q64y1k7Zf?p16&vd_sourceaed4c634975918b14b7354ec93ce5389 David数据库可以用基因ID或者基因名。 KEGG数据库使用&am…

linux环境下手动安装mysql

没想到兜兜转转这么些年&#xff0c;今天申请个云服务器用来搭建求生2服务器&#xff0c;先用mysql来测试&#xff0c;结果还是花了相当久的时间。 基本所有单节点部署应用到linux环境&#xff0c;都三个流程&#xff1a; 1 下载安装包 2 解压修改配置文件 3 运行启动脚本 我们…

2024年最新软件测试学习路线图(从入门到精通)

六维全息课程注重综合能力培养&#xff0c;从入学到职后一站式服务测试开发人才。2024年最新软件测试学习路线图&#xff0c;从入门到精通一应俱全。 9阶段专业课11大专项测试项目 适应互联网企业测试开发需求。 对于想入行学软件测试的新手来说&#xff0c;首先就需要一个高效…

Qt自定义信号、带参数的信号、lambda表达式和信号的使用

整个部分知识通过一个跳转窗口的项目来体现 第一个页面 #include "test.h" #include <qdebug.h> test::test(QWidget *parent): QDialog(parent) {ui.setupUi(this);/** &s 信号发出者* &subWidget::mySignals 处理的信号&#xff0c; &发送者类…

携手鲲鹏,长亮科技加速银行核心系统升级

新经济周期下&#xff0c;银行净息差持续收窄、盈利压力加大、市场竞争日趋加剧。同时&#xff0c;国家相关政策不断出台&#xff0c;对金融科技的自主创新与安全可控提出了更高要求。 在这样的大背景下&#xff0c;银行业的数字化转型已经步入深水区。其中&#xff0c;核心系统…