物联网网关Web服务器--CGI开发实例BMI计算
本例子通一个计算体重指数的程序来演示Web服务器CGI开发。
硬件环境:飞腾派开发板(国产E2000处理器)
软件环境:飞腾派OS(Phytium Pi OS)
硬件平台参考另一篇博客:国产化ARM平台-飞腾派开发板硬件与系统
lighttpd服务器部署参考另一篇博客:物联网网关Web服务器--lighttpd服务器部署与应用测试
1、部署与运行效果
//启动服务器
user@phytiumpi:/var/www$ sudo service lighttpd start//服务器根目录/var/www部署如下目录与文件
user@phytiumpi:/var/www$ tree
.
`-- html|-- bmi.png|-- bmi_index.png|-- cgi-bin| `-- bmi.cgi`-- index.html2 directories, 4 files//文件权限如下
user@phytiumpi:/var/www$ ls -lh html/*
-rw-r--r-- 1 root root 36K Jan 16 11:07 html/bmi.png
-rw-r--r-- 1 root root 13K Jan 16 14:08 html/bmi_index.png
-rw-r--r-- 1 root root 688 Jan 16 11:07 html/index.htmlhtml/cgi-bin:
total 16K
-rwxr-xr-x 1 root root 15K Jan 16 13:51 bmi.cgi//bmi.cgi文件类型
user@phytiumpi:/var/www$ file html/cgi-bin/bmi.cgi
html/cgi-bin/bmi.cgi: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=f39d7a4a7551ef3e3b4eba59a12959d4bc636032, for GNU/Linux 3.7.0, not stripped
-
浏览器运行
输入身高与体重信息,点击“计算”按钮,会提交当前网页中的表单数据到Web服务器并返回计算后的BMI数据。
2、Index网页文件说明
index.html是web服务器默认的页面文件,主要作用就是显示一个静态页面,提交当前页面后指定的cgi程序执行处理。
//action 指定了cgi-bin\bmi.cgi为提交后执行的程序文件
<form action="cgi-bin\bmi.cgi" method="get">
index.html源码:
<html>
<body>
<div align="center">
<form action="cgi-bin\bmi.cgi" method="get"> <table> <tr><td rowspan="3"><img src="bmi.png" hight="60" width="120"></td><td align="center" colspan="3"><h2>体重指数(BMI)计算器</h2></td></tr><tr><td >身高 : <input type="number" name="cm" min="1" max="300" size="3"> cm </td><td >体重 : <input type="number" name="kg" min="1" max="500" size="3"> kg </td><td align="center" ><input type=submit value=" 计 算 " size="16"> </td></tr><tr><td align="center" colspan="3">BMI = <input type="text" name="ret" value="" size="3" readonly></tr> </table>
</form>
</br><img src=bmi_index.png >
</div>
</body>
</html>
3、HTTP 请求处理功能说明
通过getvalue.h头文件实现。
宏定义和全局变量
#define FIELD_LEN 60
#define NV_PAIRS 15 typedef struct name_value_st{char name[FIELD_LEN + 1];char value[FIELD_LEN + 1];
} name_value;name_value name_val_pairs[NV_PAIRS];
int num_pairs = 0;/*pairs number*/
const char *M = NULL;
const char *L = NULL;
const char *S = NULL;
static int iread = 0;
-
FIELD_LEN
宏定义了每个名称或值的最大长度为 60。 -
NV_PAIRS
宏定义了可以处理的名称 - 值对的最大数量为 15。 -
name_value
结构体包含两个字符数组name
和value
,分别用于存储名称和值,长度为FIELD_LEN + 1
。 -
name_val_pairs
是name_value
结构体的数组,用于存储多个名称 - 值对。 -
num_pairs
用于记录实际存储的名称 - 值对的数量。 -
M
、L
、S
是指向常量字符的指针,初始化为NULL
,可能用于存储请求方法、内容长度和查询字符串。 -
iread
是静态整型变量,可能用于记录读取值的次数。
函数声明
void unescape_url(char *url);
void set_env(const char *r_mth, const char *c_len,const char *q_str);
char* get_value(const char *name);
int get_input(void);
void send_error(char *error_test);
char x2c(char *what);
void load_nv_pair(char *tmp_buffer, int nv_entry_number_to_load);
-
unescape_url(char *url)
:对 URL 进行转义处理。 -
set_env(const char *r_mth, const char *c_len,const char *q_str)
:设置环境变量,将传入的三个参数存储到全局指针M
、L
和S
中。 -
get_value(const char *name)
:根据传入的名称查找并返回对应的value
。 -
get_input(void)
:获取输入数据,根据请求方法(POST 或 GET)将数据存储在ip_data
中,并将数据解析为名称 - 值对存储在name_val_pairs
中。 -
send_error(char *error_text)
:输出错误信息,以 HTML 格式输出错误信息。 -
x2c(char *what)
:将十六进制表示的字符转换为对应的 ASCII 字符。 -
load_nv_pair(char *tmp_buffer, int nv_entry_number_to_load)
:将tmp_buffer
中的名称 - 值对加载到name_val_pairs
数组的指定条目中。
set_env(const char *r_mth, const char *c_len,const char *q_str)
void set_env(const char *r_mth, const char *c_len,const char *q_str)
{M = r_mth;L = c_len;S = q_str;
}
-
功能:将传入的三个参数
r_mth
、c_len
和q_str
分别赋值给全局指针M
、L
和S
,用于存储环境信息。
get_value(const char *name)
char* get_value(const char *name)
{int nv_entry_number = 0;int i = 0;char* val = NULL;char *tname = NULL;if(iread == 0){ if (!get_input()){return "error";exit(EXIT_FAILURE);}}for(i = 0; i < num_pairs; i++ ){ val = name_val_pairs[nv_entry_number].value;tname = name_val_pairs[nv_entry_number].name;nv_entry_number++;if( strcmp(tname,name) == 0 ){ break;}else{ val = NULL; tname = NULL;}}iread++;//read value timesreturn val; exit(EXIT_SUCCESS);
}
-
功能:
-
首先,如果
iread
为 0,则调用get_input()
函数获取输入数据。如果get_input()
失败,返回"error"
并终止程序。 -
然后遍历
name_val_pairs
数组,比较每个名称 - 值对的名称部分和传入的name
,如果匹配,将对应的value
存储在val
中。 -
增加
iread
的值,表示读取值的次数。 -
最后返回找到的
value
,如果未找到,返回NULL
。
-
get_input(void)
int get_input(void)
{int nv_entry_number = 0;int got_data = 0;char *ip_data = NULL;int ip_length = 0;char tmp_buffer[(FIELD_LEN * 2) + 2];int tmp_offset = 0;char *tmp_char_ptr = NULL;int chars_processed = 0;tmp_char_ptr = (char*)M;if ( tmp_char_ptr){if(strcmp(tmp_char_ptr, "POST") == 0){tmp_char_ptr = (char*)L;if (tmp_char_ptr){ip_length = atoi(tmp_char_ptr);ip_data = malloc(ip_length + 1);if (fread(ip_data, 1, ip_length, stdin)!= ip_length){send_error("Bad read from stdin");return(0);}ip_data[ip_length] = '\0';got_data = 1;}}}tmp_char_ptr = (char*)M;if ( tmp_char_ptr){if(strcmp(tmp_char_ptr, "GET") == 0){tmp_char_ptr = (char*)S;if (tmp_char_ptr){ip_length = strlen(tmp_char_ptr);ip_data = malloc(ip_length + 1);strcpy(ip_data, (char*)S);ip_data[ip_length] = '\0';got_data = 1;}}}if (!got_data){send_error("No data received");}if (ip_length <= 0){send_error("Input length <= 0");return(0);}memset(name_val_pairs, '\0', sizeof(name_val_pairs));tmp_char_ptr = ip_data;while (chars_processed <= ip_length && nv_entry_number < NV_PAIRS){tmp_offset = 0;while (*tmp_char_ptr && *tmp_char_ptr!= '&' && tmp_offset < FIELD_LEN){tmp_buffer[tmp_offset] = *tmp_char_ptr;tmp_offset++;tmp_char_ptr++;chars_processed++;}tmp_buffer[tmp_offset] = '\0';load_nv_pair(tmp_buffer, nv_entry_number);tmp_char_ptr++;nv_entry_number++;}free(ip_data);ip_data = NULL;return(1);
}
-
功能:
-
首先,通过
M
检查请求方法。 -
如果是
POST
方法,通过L
获取内容长度,分配足够的内存给ip_data
,使用fread
从标准输入读取数据,处理读取错误。 -
如果是
GET
方法,通过S
获取查询字符串,分配内存给ip_data
,复制查询字符串,添加字符串结束符。 -
检查是否有数据,如果没有数据,调用
send_error
函数报错。 -
检查输入长度是否小于等于 0,若是则报错。
-
清空
name_val_pairs
数组。 -
遍历
ip_data
,将数据存储在tmp_buffer
中,遇到&
符号或达到FIELD_LEN
长度时,调用load_nv_pair
函数将数据存储到name_val_pairs
数组中。 -
释放
ip_data
的内存。
-
send_error(char *error_text)
void send_error(char *error_text)
{printf("Content-Type: text/html\r\n");printf("\r\n");printf("Woops:- %s\r\n",error_text);
}
-
功能:输出 HTML 头信息和错误信息,用于向用户反馈错误信息。
load_nv_pair(char *tmp_buffer, int nv_entry)
void load_nv_pair(char *tmp_buffer, int nv_entry)
{int chars_processed = 0;char *src_char_ptr = NULL;char *dest_char_ptr = NULL;src_char_ptr = tmp_buffer;dest_char_ptr = name_val_pairs[nv_entry].name;while (*src_char_ptr && *src_char_ptr!= '=' && chars_processed < FIELD_LEN){if (*src_char_ptr == '+'){*dest_char_ptr = ' ';}else{*dest_char_ptr = *src_char_ptr;}dest_char_ptr++;src_char_ptr++;chars_processed++;}if (*src_char_ptr == '='){num_pairs++;src_char_ptr++;dest_char_ptr = name_val_pairs[nv_entry].value;chars_processed = 0;while (*src_char_ptr && *src_char_ptr!= '=' && chars_processed < FIELD_LEN){if (*src_char_ptr == '+'){*dest_char_ptr = ' ';}else{*dest_char_ptr = *src_char_ptr;}dest_char_ptr++;src_char_ptr++;chars_processed++;}}unescape_url(name_val_pairs[nv_entry].name);unescape_url(name_val_pairs[nv_entry].value);
}
-
功能:
-
将
tmp_buffer
中的数据解析为名称 - 值对,将名称存储在name_val_pairs[nv_entry].name
中,将值存储在name_val_pairs[nv_entry].value
中。 -
将
+
替换为空格。 -
调用
unescape_url
函数对名称和值进行 URL 转义处理。
-
unescape_url(char *url)
void unescape_url(char *url)
{int x,y;for (x=0,y=0; url[y]; ++x,++y ){if ( (url[x] = url[y]) == '%'){url[x] = x2c(&url[y+1]);y += 2;}}url[x] = '\0';
}
-
功能:
-
遍历
url
字符串。 -
当遇到
%
时,调用x2c
函数将后面的两个字符转换为对应的 ASCII 字符。
-
x2c(char *what)
char x2c(char *what)
{register char digit;digit = (what[0] >= 'A'? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));digit *= 16;digit += (what[1] >= 'A'? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));return(digit);
}
-
功能:将十六进制表示的字符(如
%xx
)转换为对应的 ASCII 字符。
4、应用功能主程序说明
通过bmi.c程序实现。关键代码分析说明如下:
set_env(getenv("REQUEST_METHOD"),getenv("CONTENT_LENGTH"),getenv("QUERY_STRING"));
-
getenv("REQUEST_METHOD")
:该函数用于获取名为REQUEST_METHOD
的环境变量的值。在 HTTP 服务器环境中,REQUEST_METHOD
通常包含请求的方法,例如GET
、POST
、PUT
等。 -
getenv("CONTENT_LENGTH")
:该函数用于获取名为CONTENT_LENGTH
的环境变量的值。在 HTTP 请求中,如果是POST
方法,CONTENT_LENGTH
表示请求体的长度。 -
getenv("QUERY_STRING")
:该函数用于获取名为QUERY_STRING
的环境变量的值。在 HTTP 的GET
请求中,QUERY_STRING
包含了 URL 中的查询部分(即?
后面的部分)。
val_cm = get_value("cm"); val_kg = get_value("kg");
-
通过getvalue.h文件中的自定义函数get_value,可根据传入的名称查找并返回对应的字符串值。
bmi.c文件源码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include "getvalue.h"int main(int argc, char *argv[])
{char *val_cm = NULL;char *val_kg = NULL;int cm,kg,len;float cm_f=0.0,kg_f=0.0,bmi=0.0;set_env(getenv("REQUEST_METHOD"),getenv("CONTENT_LENGTH"),getenv("QUERY_STRING")); val_cm = get_value("cm"); val_kg = get_value("kg"); cm = atoi(val_cm);kg = atoi(val_kg);cm_f = (cm + 0.0) / 100;kg_f = kg + 0.0;bmi = kg_f/(cm_f*cm_f);//计算bmi数值//下面输出信息都是HTML文件输出printf( "Content-type:text/html\n\n" ); printf("<html><body><div align=\"center\">\n");//输出调试信息printf("Debug INFO:CM=%f,KG=%f,BMI=%f \n",cm_f,kg_f,bmi);printf("<form action=\"bmi.cgi\" method=\"get\"><table> \n");printf("<tr><td rowspan=\"3\"><img src=\"../bmi.png\" hight=\"60\" width=\"120\"></td> \n");printf("<td align=\"center\" colspan=\"3\"><h2>体重指数(BMI)计算器</h2></td></tr> \n");printf("<tr><td >身高 : <input type=\"number\" name=\"cm\" min=\"1\" max=\"300\" size=\"3\"> cm </td> \n");printf("<td >体重 : <input type=\"number\" name=\"kg\" min=\"1\" max=\"500\" size=\"3\"> kg </td> \n");printf("<td align=\"center\" ><input type=submit value=\" 计 算 \" size=\"16\"> </td></tr> \n");printf("<tr><td align=\"center\" colspan=\"3\">BMI = \n");if(bmi == 0.0)printf("<input type=\"text\" name=\"ret\" value=\" \" size=\"3\" readonly></tr> \n");elseprintf("<input type=\"text\" name=\"ret\" value=\" %.1f \" size=\"3\" readonly></tr> \n",bmi); printf("</table></form></br><img src=\"../bmi_index.png\" > \n");printf("</div></body> </html> \n");return 0;
}
相关文章:

物联网网关Web服务器--CGI开发实例BMI计算
本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境:飞腾派开发板(国产E2000处理器) 软件环境:飞腾派OS(Phytium Pi OS) 硬件平台参考另一篇博客:国产化ARM平台-飞腾派开发板…...

计算机网络 (51)鉴别
前言 计算机网络鉴别是信息安全领域中的一项关键技术,主要用于验证用户或信息的真实性,以及确保信息的完整性和来源的可靠性。 一、目的与重要性 鉴别的目的是验明用户或信息的正身,对实体声称的身份进行唯一识别,以便验证其访问请…...

【Docker】搭建一个功能强大的自托管虚拟浏览器 - n.eko
前言 本教程基于群晖的NAS设备DS423的docker功能进行搭建,DSM版本为 DSM 7.2.2-72806 Update 2。 n.eko 支持多种类型浏览器在其虚拟环境中运行,本次教程使用 Chromium 浏览器镜像进行演示,支持访问内网设备和公网地址。 简介 n.eko 是…...

论文笔记(六十二)Diffusion Reward Learning Rewards via Conditional Video Diffusion
Diffusion Reward Learning Rewards via Conditional Video Diffusion 文章概括摘要1 引言2 相关工作3 前言4 方法4.1 基于扩散模型的专家视频建模4.2 条件熵作为奖励4.3 训练细节 5 实验5.1 实验设置5.2 主要结果5.3 零样本奖励泛化5.4 真实机器人评估5.5 消融研究 6 结论 文章…...

探索 Stable-Diffusion-Webui-Forge:更快的AI图像生成体验
目录 简介🌟 主要特点📥 安装步骤1. 下载2. 配置环境和安装依赖3. 模型目录说明 🚀 运行 Stable-Diffusion-Webui-Forge1. 进入项目目录2. 运行项目3. 打开页面 🎨 使用体验常见问题📝 小结 简介 Stable-Diffusion-We…...

Redis使用基础
1 redis介绍 Redis(Remote Dictionary Server ),即远程字典服务 ! 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。 使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并…...

PyCharm+RobotFramework框架实现UDS自动化测试- (四)项目实战0x10
1.环境搭建 硬件环境:CANoe、待测设备(包含UDS诊断模块) 2.pythonPyCharm环境 pip install robotframework pip install robotframework-ride pip install openpyxl pip install udsoncan pip install python-can pip install can-isotp3…...

【TCP】rfc文档
tcp协议相关rfc有哪些 TCP(传输控制协议)是一个复杂的协议,其设计和实现涉及多个RFC文档。以下是一些与TCP协议密切相关的RFC文档列表,按照时间顺序排列,涵盖了从基础定义到高级特性和优化的各个方面: 基…...

【SpringCloud】黑马微服务学习笔记
目录 1. 关于微服务 ?1.1 微服务与单体架构的区别 ?1.2 SpringCloud 技术 2. 学习前准备 ?2.1 环境搭建 ?2.2 熟悉项目 3. 正式拆分 ?3.1 拆分商品功能模块 ?3.2 拆分购物车功能模块 4. 服务调用 ?4.1 介绍 ?4.2 RustTemplate?的使用 4.3 服务治理-注册中…...
梯度提升决策树树(GBDT)公式推导
### 逻辑回归的损失函数 逻辑回归模型用于分类问题,其输出是一个概率值。对于二分类问题,逻辑回归模型的输出可以表示为: \[ P(y 1 | x) \frac{1}{1 e^{-F(x)}} \] 其中 \( F(x) \) 是一个线性组合函数,通常表示为ÿ…...

【MySQL】表的基本操作
??表的基本操作 文章目录: 表的基本操作 创建查看表 创建表 查看表结构 表的修改 表的重命名 表的添加与修改 删除表结构 总结 前言: 在数据库中,数据表是存储和组织数据的基本单位,对于数据表的操作是每个程序员需要烂熟…...

项目中使用的是 FastJSON(com.alibaba:fastjson)JSON库
从你的 pom.xml 文件中可以看到,项目明确依赖了以下 JSON 库: FastJSON: <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version> </depende…...
Flutter中PlatformView在鸿蒙中的使用
Flutter中PlatformView在鸿蒙中的使用 概述在Flutter中的处理鸿蒙端创建内嵌的鸿蒙视图创建PlatformView创建PlatformViewFactory创建plugin,注册platformview注册插件 概述 集成平台视图(后称为平台视图)允许将原生视图嵌入到 Flutter 应用…...

音频入门(一):音频基础知识与分类的基本流程
音频信号和图像信号在做分类时的基本流程类似,区别就在于预处理部分存在不同;本文简单介绍了下音频处理的方法,以及利用深度学习模型分类的基本流程。 目录 一、音频信号简介 1. 什么是音频信号 2. 音频信号长什么样 二、音频的深度学习分…...
规避路由冲突
路由冲突是指在网络中存在两个或多个路由器在进行路由选择时出现矛盾,导致网络数据包无法正确传输,影响网络的正常运行。为了规避路由冲突,可以采取以下措施: 一、合理规划IP地址 分配唯一IP:确保每个设备在网络中都有…...

SQLmap 自动注入 -02
1: 如果想获得SQL 数据库的信息,可以加入参数: -dbs sqlmap -u "http://192.168.56.133/mutillidae/index.php?pageuser-info.php&usernamexiaosheng&passwordabc&user-info-php-submit-buttonViewAccountDetails" --batch -p username -dbs…...

4.JoranConfigurator解析logbak.xml
文章目录 一、前言二、源码解析GenericXMLConfiguratorlogback.xml解析通过SaxEvent构建节点model解析model节点DefaultProcessor解析model 三、总结 一、前言 上一篇介绍了logback模块解析logback.mxl文件的入口, 我们可以手动指定logback.xml文件的位置, 也可以使用其它的名…...
React 19 新特性总结
具体详见官网: 中文:React 19 新特性 英文:React 19 新特性 核心新特性 1. Actions 解决问题:简化数据变更和状态更新流程 以前需要手动处理待定状态、错误、乐观更新和顺序请求需要维护多个状态变量(isPending, error 等) 新…...

kafka学习笔记6 ACL权限 —— 筑梦之路
在Kafka中,ACL(Access Control List)是用来控制谁可以访问Kafka资源(如主题、消费者组等)的权限机制。ACL配置基于Kafka的kafka-acls.sh工具,能够管理对资源的读取、写入等操作权限。 ACL介绍 Kafka的ACL是…...
【Java】Java抛异常到用户界面公共封装
前言 在Java中处理代码运行异常是常见的技术点之一,我们大部分会使用封装的技巧将异常进行格式化输出,方便反馈给用户界面,也是为了代码复用 看看这行代码是怎么处理异常的 CommonExceptionType.SimpleException.throwEx("用户信息不…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...