sending data->索引问题

本文详细介绍了通过在CREATED_字段上创建索引来优化MySQL查询性能的过程,有效减少了Sendingdata状态的时间,显著提高了查询效率。分析了导致问题的查询语句和创建索引前后的性能对比,提供了有效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近,有两次Tomcat 响应很慢,直到宕机。期间登录mysql server ,使用show processlist均能看到大量的sending data 状态。查看官方的关于sending data说明:
  • Sending data

    The thread is processing rows for a statement and also is sending data to the client.

意思是正在将查询结果往客户端发送。


开始一直以为是max_allow_packet的值太小,并且认为程序有问题导致tomcat响应很慢。mysql 将查询的结果发送给前端tomcat.而此时tomcat因程序问题响应很慢,所以mysql将查询到的结果一直处理Sending data状态。但是让我不明白的是我前端有两个同样的tomcat,为什么同时都有问题。

后来仔细分析了两次出现大量Sending data的sql语句。发现大部分都是针对一个表上的查询。而且where 条件的那个字段值只有几种,大部分都是相同的值。这样在上面建索引根本没有任何的效果。同时用profile验证了这个sql查询每个阶段所需要的时间。发现在Sending data 上花费的时间最长。expalin 出来的结果显示共扫描了161172行。

mysql> explain select P.ID_ FROM NEWSFEEDDIST P WHERE RELATIONSHIP_ = 1 and CREATED_ >= DATE_SUB(NOW(),INTERVAL 18 DAY) AND CREATED_ < DATE_SUB(NOW(),INTERVAL 17 DAY);        +----+-------------+-------+------+-------------------------+-------------------------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys           | key                     | key_len | ref   | rows   | Extra       |
+----+-------------+-------+------+-------------------------+-------------------------+---------+-------+--------+-------------+
| 1 | SIMPLE      | P     | ref | SNS_NEWSFEEDDIST_REL_IN | SNS_NEWSFEEDDIST_REL_IN | 3       | const | 161172 | Using where |
+----+-------------+-------+------+-------------------------+-------------------------+---------+-------+--------+-------------+

mysql> set profiling =1;

mysql> SELECT COUNT(1), MAX(P.CREATED_) FROM NEWSFEEDDIST P WHERE RELATIONSHIP_ = 1 AND CREATED_ >= DATE_SUB(NOW(),INTERVAL 19 DAY) AND CREATED_ < DATE_SUB(NOW(),INTERVAL 18 DAY);

mysql> show profile for query 1;
+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.060039 |
| checking query cache for query | 0.000161 |
| Opening tables                 | 0.000034 |
| System lock                    | 0.000019 |
| Table lock                     | 0.000021 |
| init                           | 0.000095 |
| optimizing                     | 0.000035 |
| statistics                     | 0.000157 |
| preparing                      | 0.000040 |
| executing                      | 0.000010 |
| Sending data                   | 1.079902 |
| end                            | 0.000018 |
| query end                      | 0.000005 |
| freeing items                  | 0.000056 |
| logging slow query             | 0.000004 |
| logging slow query             | 0.000053 |
| cleaning up                    | 0.000007 |
+--------------------------------+----------+
17 rows in set (0.00 sec)

既然 RELATIONSHIP_ 字段上的索引无效,那么针对这个sql我在CREATED_字段上创建了一个索引。再次运行
mysql>alter table NEWSFEEDDIST add index(CREATED_);
mysql>SELECT COUNT(1), MAX(P.CREATED_) FROM NEWSFEEDDIST P WHERE RELATIONSHIP_ = 1 AND CREATED_ >= DATE_SUB(NOW(),INTERVAL 19 DAY) AND CREATED_ < DATE_SUB(NOW(),INTERVAL 18 DAY);
mysql>show profile for query 3;
+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000048 |
| checking query cache for query | 0.000130 |
| Opening tables                 | 0.000028 |
| System lock                    | 0.000011 |
| Table lock                     | 0.000019 |
| init                           | 0.000076 |
| optimizing                     | 0.000031 |
| statistics                     | 0.000183 |
| preparing                      | 0.000034 |
| executing                      | 0.000011 |
| Sending data                   | 0.007954 |
| end                            | 0.000013 |
| query end                      | 0.000009 |
| freeing items                  | 0.000088 |
| logging slow query             | 0.000009 |
| cleaning up                    | 0.000011 |
+--------------------------------+----------+
16 rows in set (0.00 sec)
此时在sending data上小了很多。而且用了CREATED_索引后扫描的行数变成了2888条

mysql>explain select P.ID_ FROM test_NEWSFEEDDIST P WHERE RELATIONSHIP_ = 1 and CREATED_ >= DATE_SUB(NOW(),INTERVAL 18 DAY) AND CREATED_ < DATE_SUB(NOW(),INTERVAL 17 DAY);                                    
+----+-------------+-------+-------+----------------------------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys                    | key      | key_len | ref | rows | Extra       |
+----+-------------+-------+-------+----------------------------------+----------+---------+------+------+-------------+
| 1 | SIMPLE      | P     | range | SNS_NEWSFEEDDIST_REL_IN,CREATED_ | CREATED_ | 9       | NULL | 2888 | Using where |
+----+-------------+-------+-------+----------------------------------+----------+---------+------+------+-------------+


这个效果还是不错的。cool


这里有个关于mysql sending data状态的解释
http://renxijun.blog.sohu.com/82906360.html

 

http://hi.baidu.com/hexie007/item/126939785b86353c714423cd

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <ctype.h> #include <stdbool.h> #include <unistd.h> #include <time.h> /* 定义常量 */ #define TCP_IP_MAXSIZE 2 #define MODBUS_MAX_REGISTERS 125 #define MAX_ADDR_STR_LEN 20 #define MAX_DATA_PACKET_SIZE 4096 #define COLLECTION_INTERVAL_MS 1000 /* 寄存器类型枚举 */ typedef enum { REG_V, /* V寄存器 */ REG_IX, /* IX寄存器 */ REG_QX, /* QX寄存器 */ REG_MX, /* MX寄存器 */ REG_MW, /* MW寄存器 */ REG_MD, /* MD寄存器 */ REG_DBX, /* DBX寄存器 */ REG_DBW, /* DBW寄存器 */ REG_DBD, /* DBD寄存器 */ REG_DB, /* DB寄存器 */ REG_UNKNOWN /* 未知类型 */ } RegType; /* 寄存器类型属性 */ typedef struct { RegType type; const char *prefix; /* 字符串前缀 */ bool is_bit_addressable; /* 是否支持位寻址 */ int byte_size; /* 字节大小(2或4) */ } RegTypeInfo; /* 寄存器类型信息表 */ static const RegTypeInfo reg_type_info[] = { {REG_V, "%V", false, 2}, {REG_IX, "%IX", false, 2}, {REG_QX, "%QX", false, 2}, {REG_MX, "%MX", true, 2}, /* 虽然支持位寻址,但byte_size为2 */ {REG_MW, "%MW", false, 2}, {REG_MD, "%MD", false, 4}, {REG_DBX, "%DBX", true, 2}, /* 虽然支持位寻址,但byte_size为2 */ {REG_DBW, "%DBW", false, 2}, {REG_DBD, "%DBD", false, 4}, {REG_DB, "%DB", false, 2}, {REG_UNKNOWN, "", false, 0} }; /* 设备参数列表结构体 */ typedef struct { int portfd; /* 485端口号 */ int plc_addr; /* PLC设备地址 */ char plc_ip[20]; /* TCP IP地址 */ int DeviceNumber; /* PLC编号 */ char DeviceNumber_s[16]; /* 采集设备集合标识 */ } DEVICE_ARGV_LIST; /* 采集多个设备 */ typedef struct { int Device_num; /* 采集PLC个数 */ DEVICE_ARGV_LIST DeviceArgvList[TCP_IP_MAXSIZE]; /* 参数列表集 */ } DEVICE_ARGV; /* 参数结构体 */ typedef struct { int ParaId; /* 参数ID */ char DataType; /* 参数数据类型 */ char RegAddress[MAX_ADDR_STR_LEN]; /* 参数地址 */ uint8_t RegByteValue[8];/* 采集到的寄存器值 */ } DEVICEID_PARAID; /* 设备数据结构体 */ typedef struct { char DeviceIdIndex; /* 参数个数 */ uint8_t TypeLen; /* DeviceType长度 */ uint8_t DeviceType[20]; /* 设备类型+ID */ DEVICEID_PARAID *DeviceParaID; /* 参数列表 */ } DEVICE_DATA; /* 设备编号结构体 */ typedef struct { char Number; /* 设备编号 */ char DeviceDataIndex; /* 数据库地址个数 */ DEVICE_DATA *DeviceData; /* 数据库集 */ } DEVICE_NUMBER; /* 设备参数主结构体 */ typedef struct { char date[14]; /* 时间 */ char DeviceNumberIndex; /* 设备数 */ char Poffset; /* 偏移 */ char SampleFre; /* 采集频率 */ char MessageId[10]; /* 消息ID */ DEVICE_NUMBER *DeviceNumber; /* 采集设备集 */ } DEVICE_PARA; /* 地址解析结果 */ typedef struct { RegType type; /* 寄存器类型 */ int base_addr; /* 基地址 */ int bit_offset; /* 位偏移 (-1表示无位偏移) */ } AddrParseResult; /* 地址分组结构 */ typedef struct AddrGroup { RegType type; /* 寄存器类型 */ int slave_addr; /* 从机地址 */ int portfd; /* 使用的485端口 */ int start_addr; /* 起始地址 */ int end_addr; /* 结束地址 */ int param_count; /* 包含的参数数量 */ DEVICEID_PARAID **params; /* 动态参数指针数组 */ int *bit_offsets; /* 位偏移数组 */ struct AddrGroup *next; /* 链表指针 */ } AddrGroup; /* 数据包结构 */ typedef struct { uint8_t data[MAX_DATA_PACKET_SIZE]; size_t size; uint32_t timestamp; } DataPacket; /* 全局变量 */ static AddrGroup *addr_groups_head = NULL; static DataPacket current_packet = {0}; /* 获取寄存器类型信息 */ const RegTypeInfo* get_reg_type_info(RegType type) { size_t i; for (i = 0; i < sizeof(reg_type_info)/sizeof(reg_type_info[0]); i++) { if (reg_type_info[i].type == type) { return &reg_type_info[i]; } } return &reg_type_info[sizeof(reg_type_info)/sizeof(reg_type_info[0]) - 1]; /* 返回UNKNOWN */ } /* 获取当前时间戳(毫秒) */ uint32_t get_current_timestamp() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint32_t)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000); } /* 解析地址(支持位偏移) */ AddrParseResult parse_address(const char *reg_addr) { AddrParseResult result = {REG_UNKNOWN, -1, -1}; char buf[MAX_ADDR_STR_LEN] = {0}; char *type_end; char *addr_part; char *dot_ptr; const RegTypeInfo* info; /* 复制地址字符串到缓冲区 */ strncpy(buf, reg_addr, MAX_ADDR_STR_LEN - 1); /* 查找寄存器类型部分 */ type_end = strchr(buf, ' '); if (!type_end) return result; /* 提取寄存器类型字符串 */ *type_end = '\0'; /* 在空格处截断 */ /* 确定寄存器类型 */ if (strcmp(buf, "%V") == 0) result.type = REG_V; else if (strcmp(buf, "%IX") == 0) result.type = REG_IX; else if (strcmp(buf, "%QX") == 0) result.type = REG_QX; else if (strcmp(buf, "%MX") == 0) result.type = REG_MX; else if (strcmp(buf, "%MW") == 0) result.type = REG_MW; else if (strcmp(buf, "%MD") == 0) result.type = REG_MD; else if (strcmp(buf, "%DBX") == 0) result.type = REG_DBX; else if (strcmp(buf, "%DBW") == 0) result.type = REG_DBW; else if (strcmp(buf, "%DBD") == 0) result.type = REG_DBD; else if (strcmp(buf, "%DB") == 0) result.type = REG_DB; else result.type = REG_UNKNOWN; /* 解析地址数值部分 */ addr_part = type_end + 1; dot_ptr = strchr(addr_part, '.'); if (dot_ptr) { /* 处理带位偏移的地址 */ *dot_ptr = '\0'; result.base_addr = atoi(addr_part); result.bit_offset = atoi(dot_ptr + 1); /* 验证是否支持位访问 */ info = get_reg_type_info(result.type); if (!info->is_bit_addressable) { result.bit_offset = -1; } } else { /* 没有位偏移 */ result.base_addr = atoi(addr_part); result.bit_offset = -1; } return result; } /* 获取从机地址 */ int get_slave_addr(DEVICE_NUMBER *dev_num) { return dev_num->Number; } /* 获取端口fd */ int get_portfd(int device_index, DEVICE_ARGV *device_argv) { int i; for (i = 0; i < device_argv->Device_num; i++) { if (device_argv->DeviceArgvList[i].DeviceNumber_s[device_index] == '1') { return device_argv->DeviceArgvList[i].portfd; } } return -1; } /* 创建新的地址分组 */ AddrGroup* create_addr_group(RegType type, int slave_addr, int portfd, int base_addr) { AddrGroup *new_group = (AddrGroup*)malloc(sizeof(AddrGroup)); if (!new_group) return NULL; new_group->type = type; new_group->slave_addr = slave_addr; new_group->portfd = portfd; new_group->start_addr = base_addr; new_group->end_addr = base_addr; new_group->param_count = 0; new_group->next = NULL; /* 初始化动态数组 */ new_group->params = (DEVICEID_PARAID**)malloc(sizeof(DEVICEID_PARAID*) * 10); new_group->bit_offsets = (int*)malloc(sizeof(int) * 10); if (!new_group->params || !new_group->bit_offsets) { free(new_group->params); free(new_group->bit_offsets); free(new_group); return NULL; } return new_group; } /* 向地址组添加参数 */ bool add_param_to_group(AddrGroup *group, DEVICEID_PARAID *param, int bit_offset) { /* 检查是否需要扩展数组 */ if (group->param_count % 10 == 0) { size_t new_size = (group->param_count + 10) * sizeof(DEVICEID_PARAID*); DEVICEID_PARAID **new_params = (DEVICEID_PARAID**)realloc( group->params, new_size); if (!new_params) return false; group->params = new_params; int *new_offsets = (int*)realloc( group->bit_offsets, (group->param_count + 10) * sizeof(int)); if (!new_offsets) return false; group->bit_offsets = new_offsets; } /* 添加参数 */ group->params[group->param_count] = param; group->bit_offsets[group->param_count] = bit_offset; group->param_count++; return true; } /* 查找匹配的地址分组 */ AddrGroup* find_matching_group(RegType type, int slave_addr, int portfd, int base_addr) { AddrGroup *current = addr_groups_head; const RegTypeInfo* info = get_reg_type_info(type); int threshold; int min_next; while (current != NULL) { if (current->type == type && current->slave_addr == slave_addr && current->portfd == portfd) { /* 检查地址连续性 (考虑阈值) */ threshold = info->byte_size / 2; /* 使用字节大小计算阈值 */ min_next = current->end_addr + threshold; if (base_addr >= current->start_addr && base_addr <= min_next) { return current; } } current = current->next; } return NULL; } /* 初始化地址分组 */ void init_addr_groups(DEVICE_PARA *device_para, DEVICE_ARGV *device_argv) { int t1, t2, t3; AddrGroup *current; AddrGroup *next; DEVICE_NUMBER *dev_num; DEVICE_DATA *dev_data; DEVICEID_PARAID *param; AddrParseResult parsed; AddrGroup *group; int slave_addr; int portfd; /* 清空现有分组 */ current = addr_groups_head; while (current != NULL) { next = current->next; free(current->params); free(current->bit_offsets); free(current); current = next; } addr_groups_head = NULL; for (t1 = 0; t1 < device_para->DeviceNumberIndex; t1++) { dev_num = &device_para->DeviceNumber[t1]; slave_addr = get_slave_addr(dev_num); portfd = get_portfd(t1, device_argv); if (portfd == -1) continue; for (t2 = 0; t2 < dev_num->DeviceDataIndex; t2++) { dev_data = &dev_num->DeviceData[t2]; for (t3 = 0; t3 < dev_data->DeviceIdIndex; t3++) { param = &dev_data->DeviceParaID[t3]; parsed = parse_address(param->RegAddress); if (parsed.base_addr < 0 || parsed.type == REG_UNKNOWN) continue; /* 查找匹配的分组 */ group = find_matching_group( parsed.type, slave_addr, portfd, parsed.base_addr); if (group) { /* 更新地址范围 */ if (parsed.base_addr < group->start_addr) { group->start_addr = parsed.base_addr; } if (parsed.base_addr > group->end_addr) { group->end_addr = parsed.base_addr; } /* 添加参数到组 */ if (!add_param_to_group(group, param, parsed.bit_offset)) { printf("Failed to add param to group!\n"); } } else { /* 创建新分组 */ AddrGroup *new_group = create_addr_group( parsed.type, slave_addr, portfd, parsed.base_addr); if (!new_group) { printf("Failed to create new group!\n"); continue; } /* 添加到链表 */ if (!addr_groups_head) { addr_groups_head = new_group; } else { new_group->next = addr_groups_head; addr_groups_head = new_group; } /* 添加第一个参数 */ if (!add_param_to_group(new_group, param, parsed.bit_offset)) { printf("Failed to add param to new group!\n"); } } } } } } /* 从位偏移中提取位值 */ uint8_t extract_bit_value(uint8_t byte_value, int bit_offset) { if (bit_offset < 0 || bit_offset > 7) return 0; return (byte_value >> bit_offset) & 0x01; } /* 模拟MODBUS读取函数 */ int modbus_read(int portfd, int slave_addr, int start_addr, int reg_count, uint8_t *buffer) { /* 实际应用中这里应调用MODBUS库函数 */ printf("Reading MODBUS: portfd=%d, slave=%d, addr=%d, count=%d\n", portfd, slave_addr, start_addr, reg_count); int i; for (i = 0; i < reg_count * 2; i++) { buffer[i] = (uint8_t)((start_addr + i) % 256); /* 模拟数据 */ } return reg_count * 2; } /* 执行单次采集 */ void perform_single_collection() { AddrGroup *current = addr_groups_head; AddrGroup *group; const RegTypeInfo* info; int reg_count; uint8_t *read_buffer; int bytes_read; int i; DEVICEID_PARAID *param; int bit_offset; AddrParseResult parsed; int addr_offset; int buffer_offset; int bytes_to_copy; uint8_t byte_value; uint8_t bit_value; while (current != NULL) { group = current; current = current->next; info = get_reg_type_info(group->type); reg_count = group->end_addr - group->start_addr + 1; /* 根据数据类型调整寄存器计数 */ reg_count = (reg_count + info->byte_size - 1) / info->byte_size; if (reg_count > MODBUS_MAX_REGISTERS) { reg_count = MODBUS_MAX_REGISTERS; } /* 分配缓冲区 */ read_buffer = (uint8_t*)malloc(reg_count * 2); if (!read_buffer) { printf("Memory allocation failed for read buffer!\n"); continue; } /* 执行MODBUS读取 */ bytes_read = modbus_read(group->portfd, group->slave_addr, group->start_addr, reg_count, read_buffer); if (bytes_read != reg_count * 2) { printf("MODBUS read error! Expected %d bytes, got %d\n", reg_count * 2, bytes_read); free(read_buffer); continue; } /* 处理每个参数 */ for (i = 0; i < group->param_count; i++) { param = group->params[i]; bit_offset = group->bit_offsets[i]; parsed = parse_address(param->RegAddress); /* 计算数据在缓冲区中的位置 */ addr_offset = parsed.base_addr - group->start_addr; buffer_offset = addr_offset * (info->byte_size / 2); /* 2字节为单位 */ if (buffer_offset < 0 || buffer_offset >= bytes_read) { printf("Invalid buffer offset: %d\n", buffer_offset); continue; } /* 处理位访问 */ if (bit_offset >= 0) { /* 位寻址:数据长度为1字节 */ byte_value = read_buffer[buffer_offset]; bit_value = extract_bit_value(byte_value, bit_offset); memset(param->RegByteValue, 0, sizeof(param->RegByteValue)); param->RegByteValue[0] = bit_value; } else { /* 非位寻址:使用寄存器类型的byte_size */ bytes_to_copy = info->byte_size; if (buffer_offset + bytes_to_copy > bytes_read) { bytes_to_copy = bytes_read - buffer_offset; } memcpy(param->RegByteValue, read_buffer + buffer_offset, bytes_to_copy); } } free(read_buffer); } } /* 将数据添加到数据包 */ void add_to_data_packet(DEVICEID_PARAID *param) { const RegTypeInfo* info; AddrParseResult parsed; size_t required_size; uint8_t data_len; /* 解析地址获取数据类型 */ parsed = parse_address(param->RegAddress); info = get_reg_type_info(parsed.type); /* 计算所需空间 */ if (parsed.bit_offset >= 0) { /* 位寻址:数据长度1字节 */ data_len = 1; } else { /* 非位寻址:使用寄存器类型的byte_size */ data_len = (uint8_t)info->byte_size; } required_size = sizeof(int) + sizeof(uint8_t) + data_len; if (current_packet.size + required_size > MAX_DATA_PACKET_SIZE) { send_data_packet(); } /* 添加时间戳(如果新包) */ if (current_packet.size == 0) { current_packet.timestamp = get_current_timestamp(); memcpy(current_packet.data, &current_packet.timestamp, sizeof(current_packet.timestamp)); current_packet.size += sizeof(current_packet.timestamp); } /* 添加参数ID */ memcpy(current_packet.data + current_packet.size, &param->ParaId, sizeof(param->ParaId)); current_packet.size += sizeof(param->ParaId); /* 添加数据长度 */ memcpy(current_packet.data + current_packet.size, &data_len, sizeof(data_len)); current_packet.size += sizeof(data_len); /* 添加数据内容 */ memcpy(current_packet.data + current_packet.size, param->RegByteValue, data_len); current_packet.size += data_len; } /* 发送数据包 */ void send_data_packet() { size_t i; if (current_packet.size == 0) return; /* 模拟发送数据包 */ printf("\n===== Sending Data Packet =====\n"); printf("Timestamp: %u\n", current_packet.timestamp); printf("Size: %zu bytes\n", current_packet.size); printf("Content:\n"); for (i = 0; i < current_packet.size; i++) { printf("%02X ", current_packet.data[i]); if ((i+1) % 16 == 0) printf("\n"); } printf("\n===============================\n\n"); /* 重置数据包 */ current_packet.size = 0; } /* 主采集循环 */ void collection_loop(DEVICE_PARA *device_para, DEVICE_ARGV *device_argv) { uint32_t start_time; uint32_t elapsed; AddrGroup *current; int i; /* 初始化分组 */ init_addr_groups(device_para, device_argv); print_addr_groups(); /* 主循环 */ while (1) { start_time = get_current_timestamp(); /* 执行采集 */ perform_single_collection(); /* 将采集到的数据添加到数据包 */ current = addr_groups_head; while (current != NULL) { for (i = 0; i < current->param_count; i++) { add_to_data_packet(current->params[i]); } current = current->next; } /* 发送数据包 */ send_data_packet(); /* 等待下一个采集周期 */ elapsed = get_current_timestamp() - start_time; if (elapsed < COLLECTION_INTERVAL_MS) { usleep((COLLECTION_INTERVAL_MS - elapsed) * 1000); } } } /* 打印分组信息 */ void print_addr_groups() { AddrGroup *current = addr_groups_head; int group_num = 0; const RegTypeInfo* info; printf("\n===== Address Groups =====\n"); while (current != NULL) { info = get_reg_type_info(current->type); printf("Group %d: %s, slave=%d, portfd=%d, addr_range=%d-%d, params=%d\n", group_num, info->prefix, current->slave_addr, current->portfd, current->start_addr, current->end_addr, current->param_count); current = current->next; group_num++; } printf("==========================\n\n"); } /* 测试地址解析 */ void test_parse_address() { const char *test_addresses[] = { "%MX 10", "%MX 10.3", "%DBD 200", "%V 123", "%QX 55", "%UNKNOWN 30", "%DBX 100.5", "%MD 500", "%DB 300" }; int i; AddrParseResult result; const RegTypeInfo* info; printf("===== Address Parsing Test =====\n"); for (i = 0; i < sizeof(test_addresses)/sizeof(test_addresses[0]); i++) { result = parse_address(test_addresses[i]); info = get_reg_type_info(result.type); printf("Address: %s\n", test_addresses[i]); printf(" Type: %s (%d)\n", info->prefix, result.type); printf(" Base: %d\n", result.base_addr); printf(" Bit offset: %d\n", result.bit_offset); printf(" Byte size: %d\n", info->byte_size); printf(" Bit addressable: %s\n", info->is_bit_addressable ? "yes" : "no"); printf("\n"); } printf("===============================\n\n"); } int main() { /* 运行地址解析测试 */ test_parse_address(); /* 初始化设备参数和采集参数 */ DEVICE_PARA device_para = {0}; DEVICE_ARGV device_argv = {0}; int i, j, k; /* 设置示例数据 */ device_para.DeviceNumberIndex = 2; device_para.DeviceNumber = (DEVICE_NUMBER*)malloc(2 * sizeof(DEVICE_NUMBER)); memset(device_para.DeviceNumber, 0, 2 * sizeof(DEVICE_NUMBER)); /* 设备1 (包含位访问) */ device_para.DeviceNumber[0].Number = 1; device_para.DeviceNumber[0].DeviceDataIndex = 1; device_para.DeviceNumber[0].DeviceData = (DEVICE_DATA*)malloc(sizeof(DEVICE_DATA)); memset(device_para.DeviceNumber[0].DeviceData, 0, sizeof(DEVICE_DATA)); device_para.DeviceNumber[0].DeviceData->DeviceIdIndex = 3; device_para.DeviceNumber[0].DeviceData->DeviceParaID = (DEVICEID_PARAID*)malloc(3 * sizeof(DEVICEID_PARAID)); strcpy(device_para.DeviceNumber[0].DeviceData->DeviceParaID[0].RegAddress, "%MX 10"); device_para.DeviceNumber[0].DeviceData->DeviceParaID[0].ParaId = 101; strcpy(device_para.DeviceNumber[0].DeviceData->DeviceParaID[1].RegAddress, "%MX 10.3"); device_para.DeviceNumber[0].DeviceData->DeviceParaID[1].ParaId = 102; strcpy(device_para.DeviceNumber[0].DeviceData->DeviceParaID[2].RegAddress, "%MD 20"); device_para.DeviceNumber[0].DeviceData->DeviceParaID[2].ParaId = 103; /* 设备2 (双字节类型) */ device_para.DeviceNumber[1].Number = 2; device_para.DeviceNumber[1].DeviceDataIndex = 1; device_para.DeviceNumber[1].DeviceData = (DEVICE_DATA*)malloc(sizeof(DEVICE_DATA)); memset(device_para.DeviceNumber[1].DeviceData, 0, sizeof(DEVICE_DATA)); device_para.DeviceNumber[1].DeviceData->DeviceIdIndex = 2; device_para.DeviceNumber[1].DeviceData->DeviceParaID = (DEVICEID_PARAID*)malloc(2 * sizeof(DEVICEID_PARAID)); strcpy(device_para.DeviceNumber[1].DeviceData->DeviceParaID[0].RegAddress, "%DBD 200"); device_para.DeviceNumber[1].DeviceData->DeviceParaID[0].ParaId = 201; strcpy(device_para.DeviceNumber[1].DeviceData->DeviceParaID[1].RegAddress, "%DBX 55.2"); device_para.DeviceNumber[1].DeviceData->DeviceParaID[1].ParaId = 202; /* 设置采集参数 */ device_argv.Device_num = 2; device_argv.DeviceArgvList[0].portfd = 1; strcpy(device_argv.DeviceArgvList[0].DeviceNumber_s, "10"); device_argv.DeviceArgvList[1].portfd = 2; strcpy(device_argv.DeviceArgvList[1].DeviceNumber_s, "01"); /* 进入采集循环 */ collection_loop(&device_para, &device_argv); /* 释放资源 */ for (i = 0; i < device_para.DeviceNumberIndex; i++) { for (j = 0; j < device_para.DeviceNumber[i].DeviceDataIndex; j++) { free(device_para.DeviceNumber[i].DeviceData[j].DeviceParaID); } free(device_para.DeviceNumber[i].DeviceData); } free(device_para.DeviceNumber); return 0; } 帮我查看这份代码有没有将同一个fd,同一个从机地址同一个采集类型(指Md,DBD等)的所有采集地址RegAddress排序后只有前后地址超过设置的阈值后才分在一个组内,实现采集地址的分组高效采集
最新发布
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值