libmodbus主机通信主要函数分析

news2025/1/4 14:22:22

文章目录

  • 一、modbus_new_rtu
      • **1. 函数声明:**
      • **2. 参数检查:**
      • **3. 内存分配:**
      • **4. 设备字符串分配与初始化:**
      • **5. 配置 RTU 参数:**
      • **6. 其他 RTU 配置:**
      • **7. 返回 `modbus_t` 上下文:**
      • **总结:**
  • 二、modbus_set_slave
      • 函数声明:
      • 代码分析:
      • **总结:**
  • 三、modbus_connect
      • `modbus_rtu_connect` 函数
      • `modbus_rtu_is_connected` 函数
      • 总结:
  • 四、modbus_write_bit
      • 1. **`modbus_write_bit` 函数:**
      • 2. **`write_single` 函数:**
      • 3. **`send_msg` 函数:**
      • 4. **`_modbus_receive_msg` 和 `check_confirmation` 函数:**
      • 总结:


一、modbus_new_rtu

1. 函数声明:

modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit)
  • 返回类型modbus_t *,返回一个指向 modbus_t 类型的指针,表示新创建的 Modbus RTU 上下文。
  • 参数
    • device:设备名称(通常是串口设备路径,如 /dev/ttyS0)。
    • baud:波特率,表示通信速度(例如 9600,19200 等)。
    • parity:奇偶校验位(‘N’ 表示无校验,‘E’ 表示偶校验,‘O’ 表示奇校验)。
    • data_bit:数据位数,通常为 8 位。
    • stop_bit:停止位,通常为 1 或 2。

2. 参数检查:

if (device == NULL || *device == 0) {
    fprintf(stderr, "The device string is empty\n");
    errno = EINVAL;
    return NULL;
}
  • 如果设备字符串为空或无效(device 为 NULL 或空字符串),打印错误消息并返回 NULL,同时设置 errnoEINVAL(无效参数错误)。
if (baud == 0) {
    fprintf(stderr, "The baud rate value must not be zero\n");
    errno = EINVAL;
    return NULL;
}
  • 检查波特率是否为 0,如果是,则返回 NULL,并设置 errnoEINVAL

3. 内存分配:

ctx = (modbus_t *) malloc(sizeof(modbus_t));
if (ctx == NULL) {
    return NULL;
}
  • modbus_t 类型的结构体分配内存。modbus_t 是 Modbus 通信的上下文结构。
_modbus_init_common(ctx);
ctx->backend = &_modbus_rtu_backend;
  • 调用 _modbus_init_common 初始化 modbus_t 结构中的公共部分。
  • 设置 ctx->backend 为 RTU 后端的结构指针(_modbus_rtu_backend)。
ctx->backend_data = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t));
if (ctx->backend_data == NULL) {
    modbus_free(ctx);
    errno = ENOMEM;
    return NULL;
}
  • modbus_rtu_t 类型的结构体分配内存,modbus_rtu_t 是与 RTU 相关的具体实现数据结构。
  • 如果分配失败,则释放已经分配的 ctx 内存,并返回 NULL

4. 设备字符串分配与初始化:

ctx_rtu = (modbus_rtu_t *) ctx->backend_data;
ctx_rtu->device = (char *) malloc((strlen(device) + 1) * sizeof(char));
if (ctx_rtu->device == NULL) {
    modbus_free(ctx);
    errno = ENOMEM;
    return NULL;
}
  • 为设备名(如串口设备路径)分配内存,并检查是否分配成功。
#if defined(_WIN32)
strcpy_s(ctx_rtu->device, strlen(device) + 1, device);
#else
strcpy(ctx_rtu->device, device);
#endif
  • 根据平台(Windows 或其他平台),使用不同的方式复制设备名字符串。

5. 配置 RTU 参数:

ctx_rtu->baud = baud;
  • 设置波特率。
if (parity == 'N' || parity == 'E' || parity == 'O') {
    ctx_rtu->parity = parity;
} else {
    modbus_free(ctx);
    errno = EINVAL;
    return NULL;
}
  • 检查传入的奇偶校验位是否合法。如果不合法(不是 'N''E''O'),则释放内存并返回 NULL
ctx_rtu->data_bit = data_bit;
ctx_rtu->stop_bit = stop_bit;
  • 设置数据位和停止位。

6. 其他 RTU 配置:

#if HAVE_DECL_TIOCSRS485
ctx_rtu->serial_mode = MODBUS_RTU_RS232;
#endif
  • 如果支持 RS485,设置串口模式。默认情况下使用 RS232 模式。
#if HAVE_DECL_TIOCM_RTS
ctx_rtu->rts = MODBUS_RTU_RTS_NONE;
ctx_rtu->onebyte_time =
    1000000 * (1 + data_bit + (parity == 'N' ? 0 : 1) + stop_bit) / baud;
ctx_rtu->set_rts = _modbus_rtu_ioctl_rts;
ctx_rtu->rts_delay = ctx_rtu->onebyte_time;
#endif
  • 配置 RTS(请求发送)信号的行为。
  • 计算每个字节传输所需的时间(以微秒为单位)。
  • 配置用于设置 RTS 的内部函数和延迟。
ctx_rtu->confirmation_to_ignore = FALSE;
  • 设置确认消息的忽略标志。

7. 返回 modbus_t 上下文:

return ctx;
  • 返回创建并初始化完成的 modbus_t 上下文指针。

总结:

该函数 modbus_new_rtu 创建并初始化了一个 Modbus RTU 的上下文结构,主要执行以下操作:

  1. 验证输入参数。
  2. 动态分配内存给 Modbus RTU 相关的结构体。
  3. 初始化 RTU 的设备名称、波特率、奇偶校验、数据位、停止位等参数。
  4. 配置 RS485 和 RTS 信号控制(如果适用)。
  5. 返回指向 modbus_t 结构的指针,以供后续 Modbus RTU 通信使用。

这种设计使得 modbus_new_rtu 函数能够创建一个专用于 Modbus RTU 的上下文对象,并将必要的硬件和通信参数封装到其中,为后续的 Modbus 通信操作做好准备。

二、modbus_set_slave

modbus_set_slave 函数的作用是设置 Modbus 通信中的从设备(Slave)的地址。它接收一个 modbus_t 类型的上下文指针(ctx)和一个整数类型的从设备地址(slave),然后调用具体 Modbus 后端的 set_slave 方法来设置从设备地址。下面我们逐步分析代码:

函数声明:

int modbus_set_slave(modbus_t *ctx, int slave)
  • 返回类型int,表示操作是否成功,通常 0 表示成功,-1 表示失败。
  • 参数
    • ctx:指向 Modbus 上下文的指针,表示当前的 Modbus 会话。
    • slave:要设置的从设备地址,通常是一个整数(例如 1 到 247),用于标识 Modbus 网络中的从设备。

代码分析:

if (ctx == NULL) {
    errno = EINVAL;
    return -1;
}
  • 检查 ctx 是否为 NULL
    • 如果 ctxNULL,说明传入的 Modbus 上下文无效,无法进行后续的操作。
    • 使用 errno = EINVAL 设置错误码为 EINVAL(无效的参数错误),并返回 -1 表示函数失败。
return ctx->backend->set_slave(ctx, slave);
  • 如果 ctx 不为 NULL,则调用 ctx->backend->set_slave 方法来设置从设备地址。
    • ctx->backend 是一个指向 Modbus 后端实现结构的指针。后端可能是 RTU 或 TCP 等不同的 Modbus 实现,它包含了不同的实现细节。
    • set_slave 是一个在后端实现中定义的函数,用来设置从设备的地址。通过 ctx->backend->set_slave 调用该函数,传入 ctxslave 参数,设置从设备地址。

总结:

  • 功能modbus_set_slave 函数的主要作用是设置 Modbus 协议中的从设备地址,通常用于后续的通信。
  • 步骤
    1. 函数首先检查传入的 ctx 是否为 NULL,如果是,则返回错误。
    2. 如果 ctx 是有效的,调用 Modbus 后端的 set_slave 函数来设置从设备地址。
  • 扩展:具体的 set_slave 实现会依赖于 Modbus 后端类型(例如 RTU 或 TCP)。后端的 set_slave 函数通常负责存储或处理从设备地址的设置。

三、modbus_connect

modbus_rtu_connect 函数

static int _modbus_rtu_connect(modbus_t *ctx)
{
    struct termios tios;
    int flags;
    speed_t speed;
    modbus_rtu_t *ctx_rtu = ctx->backend_data;
  • 变量定义
    • struct termios tios:用于保存和设置串行端口的配置参数。
    • int flags:用于保存打开串行端口时的标志。
    • speed_t speed:用于保存串行通信的波特率。
    • modbus_rtu_t *ctx_rtu:指向 Modbus RTU 后端数据结构的指针,包含与 RTU 设备通信相关的参数。
if (ctx->debug) {
    printf("Opening %s at %d bauds (%c, %d, %d)\n",
           ctx_rtu->device,
           ctx_rtu->baud,
           ctx_rtu->parity,
           ctx_rtu->data_bit,
           ctx_rtu->stop_bit);
}
  • 如果 ctx->debugtrue,打印串口打开的调试信息,包括设备名、波特率、校验类型、数据位数和停止位。
flags = O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
  • 串口配置标志
    • O_RDWR:以读写模式打开文件。
    • O_NOCTTY:不将程序设置为控制终端。
    • O_NDELAY:打开时不等待连接建立,允许继续执行。
    • O_EXCL:以排他模式打开设备,确保不会被其他进程使用。
    • O_CLOEXEC:在执行 exec 时关闭文件描述符(在支持的平台上)。
ctx->s = open(ctx_rtu->device, flags);
if (ctx->s < 0) {
    if (ctx->debug) {
        fprintf(stderr,
                "ERROR Can't open the device %s (%s)\n",
                ctx_rtu->device,
                strerror(errno));
    }
    return -1;
}
  • 打开串口设备:使用 open 系统调用打开设备文件。如果打开失败,输出错误信息并返回 -1
tcgetattr(ctx->s, &ctx_rtu->old_tios);
memset(&tios, 0, sizeof(struct termios));
  • 保存原始的串口配置:使用 tcgetattr 获取当前串口的设置,保存在 ctx_rtu->old_tios 中。
  • 清空新的串口配置:将 tios 结构体初始化为全零,准备设置新的串口参数。
if (9600 == B9600) {
    speed = ctx_rtu->baud;
} else {
    speed = _get_termios_speed(ctx_rtu->baud, ctx->debug);
}
  • 设置波特率:根据 ctx_rtu->baud 设置串口的波特率,如果是在 9600 波特率的情况下,直接使用 B9600,否则调用 _get_termios_speed 函数获取对应的波特率常量。
if ((cfsetispeed(&tios, speed) < 0) || (cfsetospeed(&tios, speed) < 0)) {
    close(ctx->s);
    ctx->s = -1;
    return -1;
}
  • 设置输入和输出的波特率。如果设置失败,关闭串口并返回 -1
tios.c_cflag |= (CREAD | CLOCAL);
tios.c_cflag &= ~CSIZE;
  • 设置控制标志:
    • CREAD:使能接收功能。
    • CLOCAL:本地连接,不让系统将串口设置为控制终端。
    • CSIZE:掩码,表示数据位数。
switch (ctx_rtu->data_bit) {
case 5:
    tios.c_cflag |= CS5;
    break;
case 6:
    tios.c_cflag |= CS6;
    break;
case 7:
    tios.c_cflag |= CS7;
    break;
case 8:
default:
    tios.c_cflag |= CS8;
    break;
}
  • 设置数据位(5、6、7 或 8 位),根据 ctx_rtu->data_bit 选择合适的设置。
if (ctx_rtu->stop_bit == 1)
    tios.c_cflag &= ~CSTOPB;
else /* 2 */
    tios.c_cflag |= CSTOPB;
  • 设置停止位(1 或 2 位)。
if (ctx_rtu->parity == 'N') {
    tios.c_cflag &= ~PARENB;
} else if (ctx_rtu->parity == 'E') {
    tios.c_cflag |= PARENB;
    tios.c_cflag &= ~PARODD;
} else {
    tios.c_cflag |= PARENB;
    tios.c_cflag |= PARODD;
}
  • 设置校验位:
    • 'N':无校验,PARENB 被清除。
    • 'E':偶校验,PARENB 设置,PARODD 清除。
    • 'O':奇校验,PARENBPARODD 都设置。
tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  • 设置输入模式:禁用规范输入模式(ICANON)、回显(ECHO)、和信号处理(ISIG)。
if (ctx_rtu->parity == 'N') {
    tios.c_iflag &= ~INPCK;
} else {
    tios.c_iflag |= INPCK;
}
  • 设置输入校验:
    • 无校验时,INPCK 清除。
    • 有校验时,INPCK 设置。
tios.c_iflag &= ~(IXON | IXOFF | IXANY);
tios.c_oflag &= ~OPOST;
  • 禁用软件流控制(IXON, IXOFF, IXANY)并设置原始输出模式(OPOST)。
tios.c_cc[VMIN] = 0;
tios.c_cc[VTIME] = 0;
  • 设置最小读取字符数为 0,并禁用读取超时(VMINVTIME)。
if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
    close(ctx->s);
    ctx->s = -1;
    return -1;
}
  • 使用 tcsetattr 设置串口配置。如果设置失败,关闭串口并返回 -1
return 0;
}
  • 如果一切设置成功,返回 0,表示连接成功。

modbus_rtu_is_connected 函数

static unsigned int _modbus_rtu_is_connected(modbus_t *ctx)
{
#if defined(_WIN32)
    modbus_rtu_t *ctx_rtu = ctx->backend_data;

    return ctx_rtu->w_ser.fd != INVALID_HANDLE_VALUE;
#else
    return ctx->s >= 0;
#endif
}
  • 功能:检查 RTU 连接是否成功。
    • 在 Windows 上,检查文件描述符是否有效(fd != INVALID_HANDLE_VALUE)。
    • 在其他系统(如 Linux),检查串口文件描述符 ctx->s 是否大于或等于 0(表示打开成功)。

总结:

  • modbus_rtu_connect 函数设置并打开 Modbus RTU 的串口设备,配置波特率、数据位、停止位、校验等参数,确保通信能够正常进行。
  • modbus_rtu_is_connected 函数用于检查 RTU 连接是否成功。

四、modbus_write_bit

modbus_write_bit 函数用于将单个线圈(coil)位(0 或 1)写入 Modbus 从设备。我们一步步分析这个函数以及它的调用关系:

1. modbus_write_bit 函数:

  • 函数的三个参数:

    • ctx:指向 modbus_t 结构体的指针,表示 Modbus 上下文(包括连接等信息)。
    • addr:目标线圈的地址(即要写入的寄存器地址)。
    • status:要写入的状态,0 或 1。
  • 函数内部:

    • 首先检查 ctx 是否为 NULL。如果是 NULL,则设置 errnoEINVAL(无效参数),并返回 -1,表示出错。
    • 否则,调用 write_single 函数来实际执行写入操作。

2. write_single 函数:

  • write_single 是实现写操作的核心函数,它接受以下参数:

    • ctx:Modbus 上下文。
    • function:Modbus 功能码,这里是写单个线圈的功能码 MODBUS_FC_WRITE_SINGLE_COIL
    • addr:寄存器地址。
    • value:要写入的值,这里是 status ? 0xFF00 : 0。如果 status 为 1,则写入 0xFF00,否则写入 0x00
  • 函数内部:

    • 调用 ctx->backend->build_request_basis 构建请求报文,req 数组存储构建的请求消息,req_length 存储消息长度。
    • 调用 send_msg 函数发送请求消息,并返回响应。如果发送成功,继续接收并处理响应消息。
    • 如果接收到的响应消息有效,则调用 check_confirmation 验证确认消息。
    • 最终返回执行结果。

3. send_msg 函数:

  • send_msg 负责将构建的消息通过串口或其他传输方式发送出去。该函数执行如下步骤:
    • 先通过 ctx->backend->send_msg_pre 对消息进行预处理(这可能与 Modbus 的协议实现或底层操作系统的设置有关)。
    • 如果启用了调试(ctx->debug),则打印发送的消息。
    • 然后,进入一个循环,调用 ctx->backend->send 发送消息。如果发送失败,根据错误类型决定是否进行错误恢复操作(如重连或清理)。
    • 如果消息发送成功,并且实际发送的字节数与期望的字节数不匹配,则设置 errnoEMBBADDATA,表示数据错误。

4. _modbus_receive_msgcheck_confirmation 函数:

  • 如果消息发送成功,接下来需要接收响应。_modbus_receive_msg 用于接收来自从设备的响应。
  • 接收到响应后,check_confirmation 函数用于检查收到的响应是否有效,并与请求进行比较,确保通信正确。

总结:

  • modbus_write_bit 函数调用了 write_single,后者负责构建请求并发送给从设备。
  • 在发送消息后,系统会等待并验证从设备的确认响应。
  • 如果发生错误(如设备断开连接),send_msg 会尝试进行重连或错误恢复。

整个流程实现了对 Modbus 从设备的单个线圈写操作。通过发送和接收 Modbus 消息,确保请求成功执行。

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

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

相关文章

AAL省电效果对比

AAL省电的原理主要是‌通过根据显示内容来降低背光&#xff0c;然后通过调节gamma来补偿显示亮度&#xff0c;从而达到省电的效果‌。具体来说&#xff0c;gamma值越高&#xff0c;灰度越低&#xff0c;图像越暗。因此&#xff0c;颜色越暗的图片越省电&#xff0c;这也是为什么…

ArcGIS中怎么进行水文分析?(思路介绍)

最近有人咨询&#xff0c;ArcGIS中怎么进行水文分析&#xff0c;大致的说一下河网提取的思路哈 解决思路&#xff1a;dem填洼→计算水流方向→计算水流累积矩阵→形成河网 dem填洼 计算水流方向 计算水流累积矩阵 用栅格计算器&#xff0c;设阈值&#xff08;自己多次尝试&…

Debian-linux运维-ssh配置(兼容Jenkins插件的ssh连接公钥类型)

系统版本&#xff1a;Debian 12.5、11.1 1 生成密钥对 可以用云服务商控制台生成的密钥对&#xff0c;也可以自己在客户端或者服务器上生成&#xff0c; 已经有密钥对就可以跳过这步 用户默认密钥文件路径为 ~/.ssh/id_rsa&#xff0c;可以在交互中指定路径&#xff0c;也可…

ZZNUOJ 1798:大小写判断(C/C++/Java)

题目描述 给定一个英文字母判断这个字母是大写还是小写。 输入 输入只包含一个英文字母c。 输出 如果c是大写字母,输出“upper”,否则输出“lower”。 样例输入 x 样例输出 lower 来源 蓝桥杯算法训练 常见的ASCII值 ASCII表中可以记下部分特殊的值(十进制)(字母从A到Z&am…

Wonder Dynamics技术浅析(二):人体姿态估计

Wonder Dynamics 的人体姿态估计模块旨在从图像或视频中检测并定位人体关键点&#xff08;如关节、肢体等&#xff09;&#xff0c;为后续的动作捕捉、虚拟角色动画等应用提供基础数据。 一、人体姿态估计概述 人体姿态估计是指从图像或视频中检测并定位人体关键点的位置&…

前端压缩字体包方法,8MB可压缩至900K!

1、先安装压缩工具 npm install font-spider -g2、新建个文件夹&#xff0c;把要压缩的字体放进去&#xff0c;然后新建一个html&#xff0c;如下图 目前没有经过压缩的字体包是接近8MB 新建的html内容如下&#xff0c;直接复制即可 解释&#xff1a; 1、在样式中定义要压缩…

mysql的索引类型和索引方法

前言 在 MySQL 中&#xff0c;索引类型和索引方法是两个不同的概念。索引类型决定了可以存储的数据种类以及索引的功能特性&#xff0c;而索引方法则定义了索引数据的组织方式和查找机制。在 MySQL 中&#xff0c;索引&#xff08;Index&#xff09;是用于加快数据检索速度的数…

七种改进爬山算法的方法

一、爬山算法 爬山算法(Hill Climbing Algorithm)是一种启发式的基于局部最优解的搜索算法,用于在给定的搜索空间中寻找全局最优解或足够好的解。它属于局部搜索算法,通常用于解决优化问题,包括连续和离散问题。 爬山算法模拟了爬山的过程,从某个随机起始点开始,不断向更…

推荐5款局域网IP扫描工具,支持电脑+Android!

在日常网络管理中&#xff0c;快速扫描局域网中的设备和IP地址是一项基本但非常重要的任务。无论是排查网络问题还是进行设备管理&#xff0c;一款好用的 IP 扫描工具都能让你事半功倍。 如何选择适合自己需求的局域网 IP 扫描工具&#xff1f;有哪些功能强大又易于上手的工具…

微信小程序调用 WebAssembly 烹饪指南

我们都是在夜里崩溃过的俗人&#xff0c;所幸终会天亮。明天就是新的开始&#xff0c;我们会变得与昨天不同。 一、Rust 导出 wasm 参考 wasm-bindgen 官方指南 https://wasm.rust-lang.net.cn/wasm-bindgen/introduction.html wasm-bindgen&#xff0c;这是一个 Rust 库和 CLI…

03-栈和队列

目录 3.1栈和队列的定义和特点 3.2栈的表示和操作的实现 顺序栈的表示和实现 Ⅰ.顺序栈的初始化 Ⅱ.顺序栈的入栈 Ⅲ.顺序栈的出栈 链栈的表示和实现 Ⅰ.链栈的初始化 Ⅱ.链栈的入栈 Ⅲ.链栈的出栈 Ⅳ.取栈顶元素 Ⅴ.判断链栈是否为空 3.3栈与递归 3.4队列的表示和操…

Vue 3.0 中 template 多个根元素警告问题

在 Vue 2.0 中&#xff0c;template 只允许存在一个根元素&#xff0c;但是这种情况在 Vue 3.0 里发生了一些变化。 在 Vue 3.0 中开始支持 template 存在多个根元素了。但是因为 VSCode 中的一些插件没有及时更新&#xff0c;所以当你在 template 中写入多个根元素时&#xf…

vue elementUI Plus实现拖拽流程图,不引入插件,纯手写实现。

vue elementUI Plus实现拖拽流程图&#xff0c;不引入插件&#xff0c;纯手写实现。 1.设计思路&#xff1a;2.设计细节3.详细代码实现 1.设计思路&#xff1a; 左侧button列表是要拖拽的组件。中间是拖拽后的流程图。右侧是拖拽后的数据列表。 我们拖动左侧组件放入中间的流…

人工智能与传统编程的主要区别是什么?

传统编程&#xff1a;开发者预先编写软件行为规则&#xff0c;代码基于程序员定义逻辑处理输入并产生确定输出&#xff0c;具有确定性、手动编写规则和结构化逻辑特点&#xff0c;如垃圾邮件分类程序基于预设关键词等规则。AI 编程&#xff1a;从数据中学习而非手动编写规则&am…

电脑tkbrep.dll缺失怎么修复?

电脑运行时常见问题解析&#xff1a;tkbrep.dll缺失的修复策略与系统维护建议 在软件开发和电脑使用的日常中&#xff0c;我们时常会遇到各种系统报错和文件缺失的问题&#xff0c;其中tkbrep.dll的缺失便是一个较为常见的例子。作为软件开发从业者&#xff0c;我深知这些问题…

Nacos源码之服务注册

1. 准备工作 ​ 我们在使用Nacos作为SpringCloud中的注册中心组件时&#xff0c;最常用到的是它的三个功能&#xff1a;服务注册、服务发现和配置中心。 ​ 现在我们单机启动多个user-client&#xff0c;当我们成功运行UserClientApplication后可以在IDEA的service一栏中找到…

2025和数集团新年献词|和合与共,生生不息

2024年12月30日&#xff0c;“和数新春会”在上海环球港凯悦酒店举行&#xff0c;和数集团董事长兼总经理唐毅、集团高管和市场骨干欢聚一堂&#xff0c;共迎新春。 告别收获的2024&#xff0c;迎来腾飞的2025。 回望来时路&#xff0c;我们在挑战中砥砺前行&#xff0c;在困…

web 开发全局覆盖文件上传身份验证漏洞利用

全局覆盖 首先认识全局变量和局部变量 再一个就是知道全局变量是全局使用的并且有个特点就是可以覆盖 这个就是全局变量我们输出一下发现 z居然等于函数内的计算值 把我们原来定义的全局变量 $z给覆盖了 看一下局部变量 这个时候 z就不会被覆盖 <?php $x1; $y2; …

Day3 微服务 微服务保护(请求限流、线程隔离、服务熔断)、Sentinel微服务保护框架、分布式事务(XA模式、AT模式)、Seata分布式事务框架

目录 1.微服务保护 1.1.服务保护方案 1.1.1 请求限流 1.1.2 线程隔离 1.1.3 服务熔断 1.2 Sentinel 1.2.1.介绍和安装 1.2.2 微服务整合 1.2.2.1 引入sentinel依赖 1.2.2.2 配置控制台 1.2.2.3 访问cart-service的任意端点 1.3 请求限流 1.4 线程隔离 1.4.1 OpenFeign整合Senti…

使用 TensorFlow 打造企业智能数据分析平台

文章目录 摘要引言平台架构设计核心架构技术栈选型 数据采集与预处理代码详解 数据分析与预测代码详解 数据可视化ECharts 配置 总结未来展望参考资料 摘要 在大数据时代&#xff0c;企业决策正越来越依赖数据分析。然而&#xff0c;面对海量数据&#xff0c;传统分析工具常因…