void NeedSpawn(struct socket *sock)
{ //InitCount表示已经创建的但是还没有接受连接的子线程;AcceptCount表示正在accept过程中的子线程
while (atomic_read(&InitCount)+atomic_read(&AcceptCount) {
kernel_thread(khttpd_child,sock,0);
atomic_inc(&InitCount);
}
}
int khttpd_child(void *TMP)
{
struct socket *sock,*newsock;
struct sock *sk;
int error;
struct proto_ops *ops;
char *Buffer;
size_t BufLen;
struct http_time *httptime;
current->session = 1;
current->pgrp = 1;
current->state |= TASK_WAKE_ONE;
sprintf(current->comm,"khttpd - request");
sock = (struct socket*)TMP;
sk = sock->sk;
sk->nonagle = 1;
sk->linger = 1;
...
error=0;
Buffer = (char*) get_free_page(GFP_KERNEL);
httptime = kmalloc(sizeof(struct http_time),GFP_KERNEL);
atomic_dec(&InitCount);
...
memset(httptime,0,sizeof(struct http_time));
while (1==1)
{
if (atomic_read(&AcceptCount)>KHTTPD_MAXACCEPT) //判断是否拥有太多的子内核线程,其实就是http处理线程
break; //如果太多就不再启动本次的了
newsock = sock_alloc();
newsock->type = sock->type;
sock->ops->dup(newsock,sock);
ops = newsock->ops;
atomic_inc(&AcceptCount);
error = ops->accept(sock,newsock,0);
atomic_dec(&AcceptCount);
...
error=HandleIncommingConnection(newsock,Buffer,&BufLen,httptime); //实际处理客户端请求
if (error<0)
{
if (HandleUserSpace(newsock,Buffer,BufLen)<0) //如果内核处理出错,那么返回给用户空间去处理,也就是交给用户空间的web服务器
ErrorXXX(newsock,-error);
}
...
}
free_page((unsigned long)Buffer);
kfree(httptime);
return 0;
}
int HandleIncommingConnection(struct socket *sock, char *Buffer, size_t *BufLen,struct http_time *httptime)
{
struct msghdr msg;
struct iovec iov;
int len;
mm_segment_t oldfs;
struct http_header Head;
...//数据初始化
oldfs = get_fs(); set_fs(KERNEL_DS);
len = sock_recvmsg(sock,&msg,1024,0);
set_fs(oldfs);
...//出错处理,出错返回500
/* Check if the request is finished */
if ((len<4))
{
int len2;
...//数据初始化
len2 = sock_recvmsg(sock,&msg,1024,MSG_DONTWAIT);
set_fs(oldfs);
interruptible_sleep_on_timeout(&sock->wait,HZ*5);
if (len2>0)
len+=len2;
}
Buffer[len+1]=0;
*BufLen = len;
ParseHeader(Buffer,len,&Head); //解析头部
if (Head.FileName[0]!=0)
{
struct file * filp;
...//出错处理,出错返回403
filp = filp_open(Head.FileName,00,O_RDONLY); //打开客户端需要的文件
...//出错处理,出错返回404
if ((filp!=NULL)&&(filp->f_dentry!=NULL))
{
int FileLength,Permission;
char *Header;
...//权限判定,访问控制功能
FileLength = (int)(filp->f_dentry->d_inode->i_size);
if (Head.IMS[0]>0)
{
time_t TIME;
TIME=mimeTime_to_UnixTime(Head.IMS);
...//出错处理,出错返回304
}
Header = HTTPHeader(Head.FileName,FileLength,filp->f_dentry->d_inode->i_mtime,httptime);
...//出错处理,出错返回500
khttp_copy_filp_to_sock(filp,sock,FileLength,Header);
if (Header)
kfree(Header);
fput(filp);
}
return 200;
}
return -404;
}
注 意以上除了成功返回200之外,别的出错码都不是返回给客户端的,而是在khttpd_child经过判断出错后,交给用户空间再处理一次,因为内核只负 责静态页面的推送而不管别的,因此内核处理不了而出错不代表用户空间的web服务器就处理不了,于是交给khttpd_child中调用的 HandleUserSpace:
int HandleUserSpace(struct socket *sock, char *ReceivedSoFar, size_t length)
{
struct msghdr msg;
struct iovec iov;
int len;
mm_segment_t oldfs;
char *Buffer;
struct socket *clientsock;
/* struct sockaddr_un name;*/
struct sockaddr_in sin;
int error,count=0;
Buffer = (char*) get_free_page(GFP_KERNEL);
...//出错处理,真的返回500
error = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&clientsock);
if (error<0)
printk("Error during creation of socket; terminating\n");
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); //注意,向回环接口也就是127.0.0.1接口发送客户端请求,这样写入的请求就会被用户空间的web服务器受到,某种意义上,这个khttpd更像 是一个web代理,在客户端和用户空间真正的web服务器之间的代理。
sin.sin_port = htons(KHTTPD_CLIENTPORT); //注意,这个端口一定要在用户空间的web服务器上配置
error = clientsock->ops->connect(clientsock,(struct sockaddr*)&sin,sizeof(sin),0); //连接真正的用户空间的web服务器,比如apache
...
SendBuffer(clientsock,ReceivedSoFar,length); //把客户端的请求发送真正的用户空间web服务器
len=1;
while ((len>0)&&(count<10000)) //这个循环中可以看出内核的khttpd就是一个代理
{
...//数据缓冲区初始化
oldfs = get_fs(); set_fs(KERNEL_DS);
len = sock_recvmsg(sock,&msg,4096,MSG_DONTWAIT); //继续从客户端浏览器接受请求
set_fs(oldfs);
...
if (len>0)
SendBuffer(clientsock,Buffer,len); //如果有请求则继续向用户空间的web服务器转发
if (len<-100)
break;
...数据缓冲区初始化
oldfs = get_fs(); set_fs(KERNEL_DS);
len = sock_recvmsg(clientsock,&msg,4096,MSG_DONTWAIT); //接受用户空间web服务器的回应
set_fs(oldfs);
if (len>0)
SendBuffer(sock,Buffer,len); //将回应转发给客户端
...
count++;
}
sock_release(clientsock);
free_page((unsigned long)Buffer);
return 0;
}
注 意,这个函数返回了,如果返回值是负数,那么就说明用户空间的web服务器也处理不了,那就是真的发生了错误,于是就要真的进行错误返回了,其实就是调用 ErrorXXX(newsock,-error)函数,此时从HandleIncommingConnection返回的错误码还保留着:
void ErrorXXX(struct socket *sock, int Error)
{
if (Error == 404)
{
Error404(sock);
return;
}
...
}
void Error404(struct socket *sock)
{
char Message[]=
"HTTP/1.0 404 File Not Found\r\nServer: KHTTPD/0.0\r\nContent-type: text/html\r\n\r\nFILE NOT FOUND!!";
SendBuffer(sock,Message,sizeof(Message)); //真正向客户端返回错误码。
}
以 上就是khttpd的大致框架了,很有意思的就是它在内核中的作用就是客户端和用户空间web服务器的代理,虽然它作为一个以加速为目的的web服务来说 已经不再需要,但是我倒是觉得它可以作为一个很好的过滤系统经过改进后继续存在,就像netfilter一样,但是netfilter拦截五元素很方便, 虽然也可以解析数据包的具体内容,但是那很耗时,而且大多数的运行netfilter的接收过滤的上下文都是软中断上下文,因此更加不确定,更不适合做像 从sk_buff中解析用户数据并且判定那些事,因此khttpd的框架可以作为很好的用户数据过滤框架在内核中存在,新的框架不再仅仅监听端口为80的 web服务,而是可以监听所有的端口,只要用户建立一个服务器套接字,那么都可以选择将此套接字加入到过滤列表中,可以通过ioctl调用很容易做到这一 点。然后可以在内核配置一张过滤表,存放每一个端口的过滤策略,这个表的格式可以参照iptables的结构设计,如果通过的话,可以将请求直接转发给用 户空间的套接字,如果没有通过验证,那么记录审计信息后返回错误。如此的设计可能没有必要,因为linux内核可能压根就不想管像用户数据那么具体的事 情,如果你非要往内核加入这个框架的话,那么过滤的策略的设置将是一场噩梦,毕竟用户数据是一个很庞大很不具体的概念,难道过滤敏感词汇吗?如果是的话, 估计敏感词汇都存在内核瞬间内存就满了,众口难调啊,即使这个想法不被应用了内核主线,那么很可能可以满足某个老板的需求,我们公司就在做一个网页防篡改 系统,我想我可以借鉴一下这个khttpd框架,然后改改,实现我们linux版的网页防篡改系统。
linux从来不在内核提供个别应用才会用到的策略,不允许策略污染机制,呵呵,即使在2.4内核时策略(khttpd)真的污染了那么一点点机制,然而 随着2.6内核的放出,仅有的污点还是被驱赶了,因为linux内核靠更好的机制就可以给用户空间提供更好的舞台,而想在这个舞台演得好需要成为好的舞者,这难道给用户编程带来了挑战,其实程序员需要的不是什么技巧,而是unix编程的哲学思想。
相关推荐
Linux中的内核KHTTPD是一种实验性的Web服务加速机制,自Linux 2.4.13版本开始引入。它的核心思想是将静态Web页面的处理功能集成到内核中,以此提高性能和效率。KHTTPD实际上是一个内核模块,可以视为一种特殊的设备...
### Linux 2.4 内核配置选项详解 #### 一、引言 本文将详细介绍 Linux 2.4 内核配置过程中所涉及的关键选项及其功能。Linux 2.4 是一个重要的里程碑版本,在服务器领域有着广泛的应用。通过合理配置内核选项,可以...
### Linux内核配置详解 #### 引言与背景 Linux内核配置是系统管理与定制过程中的关键步骤,它允许用户根据自身需求调整内核功能,优化系统性能,支持特定硬件,以及增强安全性。本文档旨在详细介绍Linux内核配置的...
### Linux 内核配置知识点详解 #### 一、引言 Linux 内核配置是一项重要的技术活动,旨在根据用户的具体需求定制操作系统的核心组件。通过适当的配置,用户可以优化系统的性能、安全性和稳定性,同时减少不必要的...
内容概要:本文详细介绍了利用Matlab、YALMIP和CPLEX实现微电网两阶段鲁棒优化经济调度的方法。首先,主问题部分通过定义决策变量如机组出力、储能充放电状态等,建立目标函数以最小化总成本,并设置相应的约束条件。接着,子问题部分模拟最恶劣场景,通过引入不确定性和惩罚系数,最大化系统成本,从而找到系统的薄弱环节。两者通过列与约束生成算法(CCG)进行迭代优化,直至达到收敛条件。文中还提供了多个实战避坑指南,如变量维度对齐、CPLEX参数调优以及不确定性集合的选择等。 适合人群:从事电力系统优化研究的专业人士,尤其是对微电网调度感兴趣的工程师和技术研究人员。 使用场景及目标:适用于需要确保微电网在面对极端天气或其他不确定性因素时仍能稳定运行的情况。主要目标是在保障系统可靠性的前提下,降低运营成本,提高经济效益。 其他说明:文章不仅提供了详细的代码实现步骤,还包括了许多实用的经验分享和技巧提示,帮助读者更好地理解和应用两阶段鲁棒优化方法。此外,还强调了在实际应用中应注意的问题,如避免过度保守、合理设定不确定集参数等。
内容概要:本文介绍了H6逆变器拓扑结构及其离网和并网仿真模型的特点。H6逆变器采用六开关器件设计,支持非单位功率因数负载、功率因数调节、共模电流抑制等功能。文中详细讨论了PR单环控制策略、锁相环(SOGI-PLL)、LC和LCL滤波器的应用,并提供了相关代码示例。此外,文章还探讨了仿真环境设置以及常见调试技巧,验证了H6逆变器在不同负载条件下的优越性能。 适合人群:从事电力电子、逆变器设计与仿真的工程师和技术研究人员。 使用场景及目标:①理解和掌握H6逆变器的工作原理和控制策略;②优化逆变器的设计参数,提高其在离网和并网场景中的性能;③通过仿真验证设计方案的有效性和可靠性。 其他说明:本文提供了丰富的代码片段和调试经验分享,有助于读者快速上手H6逆变器的实际应用。
内容概要:本文详细介绍了松下FP-X系列PLC在空调冷冻泵模拟量控制中的应用,特别是AFPX-TC2模拟量输入模块和AFPX-DA2模拟量输出模块的使用方法。文章涵盖了硬件连接、手动控制程序、自动控制程序以及模式切换逻辑的设计。通过这些模块和程序,可以实现对冷冻泵转速的手动和自动控制,确保系统的稳定性和高效性。文中还提供了详细的代码示例和调试技巧,如PID参数调整、信号量程转换、无扰动模式切换等。 适合人群:从事工业自动化控制领域的工程师和技术人员,尤其是熟悉PLC编程和模拟量控制的人士。 使用场景及目标:适用于需要对空调冷冻泵进行精确控制的工程项目,旨在提高系统的响应速度和稳定性,减少人工干预,提升工作效率。 其他说明:文章不仅提供了理论指导,还包括了许多实用的经验和注意事项,如硬件接线细节、常见问题解决方法等,有助于读者快速掌握并应用于实际项目中。
内容概要:本文详细介绍了如何利用COMSOL软件在光子晶体超表面中实现偏离Gamma点的BICs(连续谱中的束缚态)合并。首先,作者通过设置偏离Gamma点的波矢,调整晶格参数如孔半径和晶格常数,成功实现了BICs的合并。接着,作者分享了多个实用技巧,如正确设置周期性边界条件、使用六重旋转对称条件以及优化网格划分方法。此外,文中提供了详细的MATLAB和COMSOL代码片段,帮助读者理解和复现实验结果。最后,作者强调了磁场涡旋对于识别BICs的重要性,并讨论了BICs合并过程中的一些反直觉现象及其背后的物理机制。 适合人群:从事光子晶体超表面研究的科研人员和技术爱好者,尤其是那些希望深入了解BICs合并机制并对COMSOL有一定基础的读者。 使用场景及目标:① 使用COMSOL进行光子晶体超表面的数值模拟;② 实现偏离Gamma点的BICs合并;③ 优化仿真参数以提高Q值和模式稳定性;④ 理解BICs合并的物理机制及其应用前景。 其他说明:本文不仅提供了理论指导,还附带了大量的实际操作步骤和代码示例,使读者能够快速上手并在实践中不断优化自己的模型。同时,作者提醒了一些常见的错误和注意事项,有助于避免不必要的调试时间。
分享一些R包,用于GBD数据库BAPC分析
内容概要:本文档详细介绍了A10 ACOS v4平台上的VRRP-A(高级虚拟路由器冗余协议)配置方法及其工作机制。VRRP-A旨在提高网络的高可用性和冗余度,支持多达八个ACOS设备作为IP互备份,适用于网关(路由)模式及单臂模式部署。文档涵盖了VRRP-A的基本概念、配置流程、主备选举机制、故障切换逻辑、浮动IP管理、配置同步、会话同步以及接口配置等内容。此外,还提供了具体的配置示例和故障切换策略模板的创建方法,以帮助管理员更好地理解和应用VRRP-A。 适合人群:具备一定网络基础知识,尤其是熟悉ACOS平台的网络管理员和工程师。 使用场景及目标:①实现多台ACOS设备之间的冗余备份,确保网络服务的连续性和稳定性;②通过配置浮动IP、主备选举、故障切换策略等,提升网络的高可用性;③利用配置同步和会话同步功能,简化管理和维护工作。 其他说明:本文档不仅提供了详细的配置指南,还通过具体示例展示了各种配置的实际操作步骤,帮助用户快速掌握VRRP-A的配置和优化技巧。此外,文档强调了VRRP-A与传统VRRP的区别,指出两者不可互操作,因此在实际部署中需要注意选择合适的协议。
内容概要:本文详细介绍了如何利用OpenSEES平台建立单柱墩模型,并深入探讨了钢筋与混凝土之间的滑移粘接及其捏缩效应。主要内容涵盖模型初始化、节点定义、边界条件设定、材料和截面定义、单元创建以及基于位移控制的滞回分析。文中提供了完整的建模过程和相关源代码,帮助读者理解并实现这一复杂结构的数值模拟。 适合人群:从事结构工程、土木工程及相关领域的研究人员和技术人员,特别是那些对钢筋混凝土结构的非线性行为感兴趣的学者。 使用场景及目标:适用于桥梁、建筑等基础设施的设计和评估,旨在提高结构在地震等极端荷载下的安全性和耐久性。通过模拟钢筋与混凝土间的粘接滑移现象,优化结构设计,增强抗震能力。 其他说明:文章不仅提供了理论背景,还包括大量实用的代码示例和实践经验分享,有助于读者快速掌握OpenSEES平台的应用技巧。同时,针对可能出现的问题给出了具体的解决方案,如收敛困难时的处理方法等。
黔轻职院团字〔2025〕5号关于开展2025年大学生社区实践计划工作的通知.zip
内容概要:本文详细介绍了基于Matlab/Simulink构建的100kW光伏发电三相并网系统的建模与仿真。系统主要包括100kW光伏模块及其MPPT控制、两级式并网逆变器(boost电路和三相桥式逆变)、复杂的控制策略(坐标变换、锁相环、dq功率控制、解耦控制、电流内环电压外环控制、SPWM调制)以及LC滤波器。文中不仅提供了详细的理论背景和技术实现方法,还展示了具体的仿真结果,验证了系统的性能。主要内容涵盖MPPT控制算法、逆变器拓扑结构、控制策略的设计与实现、LC滤波器的作用及效果评估。 适合人群:从事电力电子、新能源发电、控制系统设计的研究人员和工程师,特别是对光伏发电并网系统感兴趣的读者。 使用场景及目标:适用于希望深入了解光伏发电并网系统工作原理和控制策略的技术人员。目标是掌握如何利用Matlab/Simulink进行光伏发电系统的建模与仿真,提高系统的发电效率和稳定性。 其他说明:文章强调了各个组件之间的协同工作对于系统整体性能的影响,并提供了大量实用的代码片段和调试技巧,有助于读者更好地理解和应用所学知识。
内容概要:本文详细介绍了电导增量法(INC)在光伏发电系统中的最大功率点跟踪(MPPT)算法。首先解释了INC算法的核心逻辑,即通过电导变化量判断爬山方向,并讨论了关键参数如阈值、步长的选择及其对系统稳定性的影响。接着探讨了PWM调制的具体实现方式,强调了V_pv_max的实时获取重要性和自适应步长策略的应用。此外,还分享了一些实用的仿真技巧,如加入噪声处理、动态调整I-V曲线以及使用卡尔曼滤波提高跟踪精度。最后,通过实验数据验证了改进后的INC算法在不同光照条件下的优越性能。 适合人群:从事光伏系统研究与开发的技术人员,尤其是对MPPT算法感兴趣的工程师。 使用场景及目标:适用于需要深入了解和优化光伏系统MPPT算法的研究和开发工作,旨在提升光伏系统的能量转换效率。 其他说明:文中提供了大量代码片段和实践经验,帮助读者更好地理解和应用电导增量法。同时提醒读者关注一些常见的陷阱和技术细节,确保仿真的准确性和可靠性。
内容概要:本文详细介绍了裂缝检测中的数据标注方法,涵盖了目标检测和语义分割两大主要技术。对于目标检测部分,重点讲解了YOLO算法的数据标注流程,包括工具选择、标注操作以及保存格式。而对于语义分割,则深入探讨了像素级标注的具体步骤,涉及多边形绘制、掩码图像生成及其优化处理。此外,还分享了一些实战经验和技巧,如如何应对复杂裂缝形态、提高标注精度的方法等。 适合人群:从事计算机视觉领域的研究人员和技术人员,尤其是专注于物体检测和图像分割方向的专业人士。 使用场景及目标:①帮助开发者掌握裂缝检测数据标注的基本技能;②提供实用的操作指南,解决实际工作中遇到的各种难题;③为构建高效准确的裂缝检测模型奠定坚实的数据基础。 其他说明:文中不仅包含了理论知识,还附带了许多具体的代码实例,有助于读者更好地理解和应用相关技术。
内容概要:本文详细介绍了半车悬架主动控制系统中MPC(模型预测控制)的应用及其调参技巧。首先解释了MPC的基本概念,即通过优化未来一段时间内的性能指标来确定当前时刻的最佳控制输入。接着展示了具体的实现步骤,包括建立状态空间模型、定义性能指标函数和采用优化算法进行求解。文中特别强调了参数调优的经验,如预测时域和控制时域的选择、权重矩阵的设计以及约束条件的设置。此外,作者还分享了一些调试细节,例如QP求解器的选项设置和作动器延迟补偿的方法。最终的效果表明,MPC能够显著提高乘坐舒适性和操控稳定性。 适合人群:从事车辆工程、自动化控制领域的研究人员和技术人员,尤其是对悬架系统和MPC感兴趣的读者。 使用场景及目标:适用于需要提升汽车行驶品质的研究项目或产品开发,旨在通过先进的控制算法改善车辆的动态性能。 其他说明:文章提供了丰富的代码片段和实践经验,有助于读者更好地理解和应用MPC技术。同时提醒读者注意参数之间的相互影响,确保系统稳定可靠地运行。
内容概要:本文详细介绍了利用Simulink模型进行高频注入以实现电机电角度精确观测的方法和技术细节。首先,通过在d轴注入特定频率的正弦波电压信号,使高频信号与转子位置产生相互作用,从而携带角度信息。其次,采用低通和带通滤波器组合对信号进行处理,分别去除高频成分并提取有用的调制信号。最后,通过锁相环结构解调相位差,得到最终的角度估计。文中还讨论了不同频率选择的影响以及启动阶段的扫频注入优化方法,并分享了一些实际应用中的经验和注意事项。 适合人群:从事电机控制系统研究与开发的专业技术人员,特别是对无位置传感器控制感兴趣的工程师。 使用场景及目标:适用于需要提高电机控制精度的应用场合,特别是在低速条件下无法使用传统位置传感器的情况下。目标是通过高频注入技术实现对电机转子位置的高精度测量,进而提升整个系统的性能。 其他说明:文中提供了大量MATLAB/Simulink代码片段作为示例,帮助读者更好地理解和实现相关算法。同时强调了实际工程实践中可能遇到的问题及其解决方案,如信噪比优化、硬件干扰排除等。
1、文件说明: Centos8操作系统texlive-csquotes-7:20180414-23.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf texlive-csquotes-7:20180414-23.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm
内容概要:本文详细介绍了风光储并网协同运行模型中的关键技术——双闭环控制策略和单极调制方法。双闭环控制策略由电流内环和电压外环构成,分别用于快速跟踪电流指令和维持输出电压稳定,确保并网电能质量。单极调制作为一种PWM技术,能够降低开关损耗,提高系统效率。文中还提供了具体的MATLAB代码示例和Simulink建模步骤,展示了如何在仿真环境中实现和优化这些控制策略。 适合人群:对风光储并网系统感兴趣的科研人员、工程师和技术爱好者。 使用场景及目标:适用于希望深入了解风光储并网系统控制机制的研究者,旨在帮助他们掌握双闭环控制和单极调制的具体实现方法,从而应用于实际项目中,提高系统的稳定性和效率。 其他说明:文章不仅提供了理论解释,还包括了详细的代码示例和仿真指导,使读者能够在实践中加深理解。此外,文中还分享了一些实用的调试技巧和注意事项,如避免过冲、设置死区时间和选择合适的仿真求解器等。
内容概要:本文详细介绍了基于S7-200 Smart PLC的速度与频率同步控制程序,主要用于卷板材生产线和造纸设备。程序通过设置速度同步地址vw10作为基准,利用频率调整系数factor[i]实现1-15回路的频率同步。此外,还支持主从单机微调功能,确保各回路能够精确同步。文中提供了具体的代码示例,解释了如何通过简单逻辑实现多机同步,并强调了微调和异常检测的重要性。对于16-30回路,考虑到设备布局和负载差异,提出了相应的优化建议,如地址映射调整和滤波算法的应用。 适合人群:从事自动化控制系统开发的技术人员,尤其是熟悉PLC编程和变频器应用的专业人士。 使用场景及目标:①帮助技术人员理解和掌握S7-200 Smart PLC在卷板材生产线和造纸设备中的速度与频率同步控制方法;②提供实用的代码示例和技术细节,便于快速部署和调试;③提高生产线的稳定性和效率,降低故障发生率。 其他说明:本文不仅涵盖了基本的同步控制逻辑,还包括了许多实际应用中的经验和技巧,如微调处理、异常检测和滤波算法等,有助于解决实际工程中的常见问题。