编程实战:自己编写HTTP服务器(系列5:执行后台shell命令)

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。


系列入口:编程实战:自己编写HTTP服务器(系列1:概述和应答)-CSDN博客

         本文介绍执行后台命令的shell.asp的实现。

目录

一、概述

二、主体代码

三、详解

3.1 参数

3.2 设置进程组和打开管道执行命令

3.3 读取数据和返回码处理


一、概述

        这个功能就相当于一个终端,不过只能执行一个命令。有什么好处看自己,可以加入自己喜欢的特性。

        入口:

        别的不说了,主体代码是doPageShell()。

二、主体代码

        主体代码如下:

		bool doPageShell(){
#ifdef _MS_VCreturn true;
#elseFILE * fp;string changedir=m_request.GetParam("changedir");string curdir=m_request.GetParam("curdir");string cmd=m_request.GetParam("command");bool noform=(m_request.GetParam("noform")=="true");bool term=(m_request.GetParam("term")=="true");long bufsize=1024*1024;char * buf=new char[bufsize];if(NULL==buf){m_respond.AppendBody("<P><FONT color=RED>内存不足</FONT><P>");return true;}//切换路径if(0!=curdir.size()){if(0!=chdir(curdir.c_str())){m_respond.AppendBody("<P><FONT color=RED>设置初始路径出错</FONT><P>"+curdir+"<P>");return true;}}if(0!=changedir.size()){if(0!=chdir(changedir.c_str())){m_respond.AppendBody("<P><FONT color=RED>切换工作路径出错</FONT><P>"+changedir+"<P>");return true;}}//执行命令if(0==cmd.size()){m_respond.AppendBody("<P>空命令<P>");}else{if(0!=setpgid(getpid(),getpid())){m_respond.AppendBody("设置进程组ID出错<P>");}if(NULL==(fp=popen((cmd+" 2>&1").c_str(),"r"))){m_respond.AppendBody("<P><FONT color=RED>无法执行,原因:popen error</FONT><P>");if(!m_respond.Flush(m_s))return true;}else{int fd=fileno(fp);int flags;fd_set fdset;struct timeval tv;tv.tv_sec=300;tv.tv_usec=0;flags = fcntl(fd, F_GETFL, 0);flags |= O_NONBLOCK;fcntl(fd, F_SETFL, flags);char * tmpp;m_respond.AppendBody("开始执行&nbsp;");m_respond.AppendBody(CHtmlDoc::HTMLEncode(cmd));m_respond.Flush(m_s);m_respond.AppendBody("<HR></HR><CODE>");while(true){FD_ZERO(&fdset);FD_SET(fd,&fdset);
#ifdef _HPOSint selectret=select(fd+1,(int *)&fdset,NULL,NULL,&tv);
#elseint selectret=select(fd+1,&fdset,NULL,NULL,&tv);
#endifif(selectret<0){LOG<<"select error"<<ENDE;}else if(0==selectret){//超时没有数据m_respond.AppendBody("注意,长时间没有收到输出.");if(!m_respond.Flush(m_s)){LOG<<"发送失败,客户端已断开,直接退出"<<ENDI;if(term){if(0!=kill(0,SIGTERM)){LOG<<"发送停止信号出错,shell会持续执行到命令结束"<<ENDE;}}return true;}continue;}else{}bool fileend=false;while(true){tmpp=fgets(buf,int(bufsize-1),fp);if(NULL==tmpp){//正常结束if(0!=feof(fp)){fileend=true;break;}if(EWOULDBLOCK==errno || EAGAIN==errno){//无数据break;}else{//出错结束m_respond.AppendBody("<P><FONT color=RED>执行出错,原因:read error</FONT><P>");m_respond.AppendBody(strerror(errno));m_respond.Flush(m_s);fileend=true;break;}}else{m_respond.AppendBody(LogToHtml(buf,false,false));m_respond.AppendBodyHtmlScroll();if(!m_respond.Flush(m_s)){LOG<<"发送失败,客户端已断开,直接退出"<<ENDI;if(term){if(0!=kill(0,SIGTERM)){LOG<<"发送停止信号出错,shell会持续执行到命令结束"<<ENDE;}}return true;}}}if(fileend)break;}m_respond.AppendBody("</CODE><HR></HR>");int ret=pclose(fp);if(0!=ret){if(WIFEXITED(ret)){sprintf(buf,"<FONT color=RED>执行完毕,返回代码 %d 。</FONT><BR>",WEXITSTATUS(ret));//(0xFF00&ret)/256);}else if(WIFSIGNALED(ret)){sprintf(buf,"<FONT color=RED>被信号终止,信号 %d 。</FONT><BR>",WTERMSIG(ret));}else if(WCOREDUMP(ret)){sprintf(buf,"<FONT color=RED>执行失败,COREDUMP。</FONT><BR>");}else{sprintf(buf,"<FONT color=RED>未知的返回值:%d。</FONT><BR>",ret);}}else sprintf(buf,"执行完毕,返回代码 %d 。<BR>",ret);m_respond.AppendBody(buf);}}if(!noform){char cwd[1024];if(NULL!=getcwd(cwd,1024)){sprintf(buf,"<FORM ACTION=\"/shell.asp\" METHOD=\"GET\" >\n""当前路径:%s<BR>""<INPUT TYPE=\"hidden\" NAME=\"curdir\" VALUE=\"%s\" >\n""切换路径到:<INPUT TYPE=\"text\" SIZE=\"30\" NAME=\"changedir\" ><BR>\n""Shell命令: <INPUT TYPE=\"text\" SIZE=\"30\" NAME=\"command\" VALUE=\"%s\">\n""<INPUT TYPE=SUBMIT VALUE=\"执行\" >\n""</FORM>\n",cwd,cwd,cmd.c_str());}else{sprintf(buf,"获取当前工作路径出错");}m_respond.AppendBody(buf);}delete[] buf;return true;
#endif}

三、详解

3.1 参数

        最关键命令参数:command,包含要执行的命令,可以是一串命令的组合,也就是你能输到控制台运行的东西都行。

        运行命令一定需要工作目录,显然不能在服务进程的工作目录下执行,谁知道会发生什么呢。目录用curdir和changedir参数来控制,如果curdir是当前工作目录,具体就是这个页面执行命令的工作目录,changedir用于切换目录,可以是相对目录。执行时首先将目录切换到curdir(因为服务进程有自己的工作目录,和期待的执行命令的工作目录不同),然后再切换到changedir,其实就是执行两次chdir()。

        代码如下:

			//切换路径if(0!=curdir.size()){if(0!=chdir(curdir.c_str())){m_respond.AppendBody("<P><FONT color=RED>设置初始路径出错</FONT><P>"+curdir+"<P>");return true;}}if(0!=changedir.size()){if(0!=chdir(changedir.c_str())){m_respond.AppendBody("<P><FONT color=RED>切换工作路径出错</FONT><P>"+changedir+"<P>");return true;}}

3.2 设置进程组和打开管道执行命令

         启动新进程一般都要设置点东西,解除新进程和服务进程的关系,主要是进程间使用进程组广播信号的问题,新进程压根不应该知道服务进程存在。

        popen()很实用的运行命令并获取输出的方法,其内部会打开单向管道,运行命令,返回输出(文件句柄)。

        为了能看到命令的所有输出,我们需要在命令后面追加“ 2>&1”将标准出错重定向到标准输出。

        相关代码如下:

				if(0!=setpgid(getpid(),getpid())){m_respond.AppendBody("设置进程组ID出错<P>");}if(NULL==(fp=popen((cmd+" 2>&1").c_str(),"r"))){m_respond.AppendBody("<P><FONT color=RED>无法执行,原因:popen error</FONT><P>");if(!m_respond.Flush(m_s))return true;}else{

        后面就是常规的从文件描述符读取数据直到结束。当然里面混合了格式化、发送,以及命令返回码的处理。

3.3 读取数据和返回码处理

       select可以检查是否有数据,这个函数一般用于socket,但是其实是针对文件描述符的。

       用fgets()逐行读取数据,如果出错errno会有各种结果,需要分别判断。

       pclose获得返回码,具体分析和进程返回码是一样的。


(这里是结束,但不是整个系列的结束)

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

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

相关文章

单片机负电压

在电子电路中我们常常需要使用负电压&#xff0c;比如说我们在使用运放的时候常常需要建立一个负电压。下面就简单的以正5V电压到负电压5V为例说一下它的电路。 通常需要使用负电压时一般会选择使用专用的负压产生芯片&#xff0c;但这些芯片都比较贵&#xff0c;比如电荷泵原理…

P1229 遍历问题

题目描述 我们都很熟悉二叉树的前序、中序、后序遍历&#xff0c;在数据结构中常提出这样的问题&#xff1a;已知一棵二叉树的前序和中序遍历&#xff0c;求它的后序遍历&#xff0c;相应的&#xff0c;已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。然而给…

剪辑师创作必备声音素材,BGM背景音效素材合集1万款

一、素材描述 本套音效包含了全面丰富的声音效果&#xff0c;如动物、运输、人群、天气、航空、军事、Foley声音等&#xff0c;以及世界各地的场景声效等&#xff0c;可能是同类音效中最为全面的&#xff0c;共由三套声音素材组合而成&#xff0c;1、熊猫背景音乐3800首&#…

宁静致远(“静”)

宁静致远是一个成语&#xff0c;读音为nng jng zh yuǎn&#xff0c;意思是只有心境平稳沉着、专心致志&#xff0c;才能厚积薄发、 有所作为。出自《淮南子:主术训》。 出处 宁静致远张铭篆刻 此句最早出自西汉初年道家刘安的《淮南子:主术训》&#xff0c;蜀汉丞相诸葛亮的…

5年增100倍6秒卖1瓶酒,酣客的“FFC模式”是什么

酣客酱酒销售模式&#xff0c;白酒FFC模式&#xff0c;白酒新零售模式设计 坐标&#xff1a;厦门&#xff0c;我是易创客肖琳 深耕社交新零售行业10年&#xff0c;主要提供新零售系统工具及顶层商业模式设计、全案策划运营陪跑等。 不知从何时起&#xff0c;营销圈开始有这么一…

Verilog 实现 i2c 协议

在时钟&#xff08;SCL&#xff09;为高电平的时候&#xff0c;数据总线&#xff08;SDA&#xff09;必须保持稳定&#xff0c;所以数据总线&#xff08;SDA&#xff09;在时钟&#xff08;SCL&#xff09;为低电平的时候才能改变。 在时钟&#xff08;SCL&#xff09;为高电平…

诸葛智能携手五大银行,以数据驱动的营销中台带来可预见增长

对于银行来说&#xff0c;客户是赖以生存的基础&#xff0c;也是保持活力的关键。尤其是大数据、人工智能等新兴技术的推动下&#xff0c;通过数据赋能产品升级和服务创新&#xff0c;深挖客户潜能&#xff0c;更是助推银行快步迈入高质量发展的新阶段。 在银行加速拥抱新质生…

文档分类DPCNN简介(pytorch实现)

文档分类DPCNN简介 DPCNN简介 模型结构区域嵌入等长卷积1/2池化DPCNN模型代码实现 DPCNN简介 论文中提出了一种基于 word-level 级别的网络-DPCNN&#xff0c;由于 TextCNN 不能通过卷积获得文本的长距离依赖关系&#xff0c;而论文中 DPCNN 通过不断加深网络&#xff0c;可以…

ATA-2021B高压放大器在光纤超声传感器中的应用

实验名称&#xff1a;超声传感性能研究 测试目的&#xff1a; 光纤马赫-曾德尔干涉仪是一种灵敏度高、结构灵活的传感结构。当在MZI上施加超声波信号时&#xff0c;会影响所涉及的干涉光之间的光程差&#xff0c;并导致干涉光谱的漂移。由于模式耦合是基于MZI的光纤传感器的关键…

脑中风也会出现眩晕?快速识别中风,一定要牢记这些!

眩晕是许多人都会经历的不适感&#xff0c;发作时仿佛整个世界都在旋转&#xff0c;可能还伴随着站立不稳、脚步虚浮、恶心等症状。然而&#xff0c;你可能不知道的是&#xff0c;这些症状在某些情况下可能是脑中风的前兆。如果不及时关注并采取相应措施&#xff0c;一旦发展为…

【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置

本节博客主要是通过“在排序数组中查找元素的第一个和最后一个位置”总结关于二分算法的左右界代码模板&#xff0c;有需要借鉴即可。 目录 1.题目2.二分边界算法2.1查找区间左端点2.1.1循环条件2.1.2求中点的操作2.1.3总结 2.2查找区间右端点2.1.1循环条件2.1.2求中点的操作2.…

O2OA平台流程催办怎么做

O2OA平台设计了灵活的消息提醒数据交互方式&#xff0c;开发者可以根据自己的需要&#xff0c;来消费消息提醒数据&#xff0c;也可以将消息提醒数据接入到Kafka消息中间件来实现消息的准实时提醒。本篇主要介绍如何在O2OA服务器中设置流程的催办提醒消息。 催办提醒服务&#…

centos无法联网解决方案(9步完成

1.打开终端&#xff0c;输入 su - root 进入到管理员模式&#xff08;-的前后都有空格哈&#xff09; 切换后&#xff0c;显示的就是root... 2.. &#xff0c;输入命令ip addr 2. 切换当前目录 cd /etc/sysconfig/network-scripts/ 3.输入命令&#xff0c;打开文件 vi /etc…

一.常见算法--动态规划

&#xff08;1&#xff09;0-1背包问题 问题描述&#xff1a; 0-1背包问题的描述&#xff1a;在n种物品中选择1个或0个第i种物品&#xff0c;装入背包容量为m的背包&#xff0c;使得背包价值达到最大。 思路与关键点&#xff1a; 用到了max函数&#xff0c;用于返回两个数之中…

为何Linux成为你不可或缺的技能

在数字化飞速发展的今天&#xff0c;无论你是IT行业的精英&#xff0c;还是其他领域的专业人士&#xff0c;掌握Linux都已经成为一项至关重要的技能。那么&#xff0c;为什么一定要学会Linux呢&#xff1f;以下文章仅供参考 1. 开源的力量&#xff1a;无限的可能性 Linux是一…

工厂自动化升级改造(3)-Modbus与MQTT的转换

什么是MQTT,Modbus,见下面文章 工厂自动化升级改造参考(01)--设备通信协议详解及选型-CSDN博客文章浏览阅读608次,点赞9次,收藏6次。>>特点:基于标准的以太网技术,使用TCP/IP协议栈,支持高速数据传输和局域网内的设备通信。>>>特点:跨平台的通信协议,…

ssl证书价格一年多少钱?如何申请?

由于行业新规&#xff0c;现在阿里云、腾讯云等几乎所有平台都不再提供一年期免费证书&#xff0c;如果需要一年期证书则需要支付一定的费用。SSL证书的价格根据类型不同几十到几百上千不等。 一年期SSL证书申请通道https://www.joyssl.com/?nid16 一年期SSL证书申请流程&am…

人工智能(一)架构

一、引言 人工智能这个词不是很新鲜&#xff0c;早就有开始研究的&#xff0c;各种推荐系统、智能客服都是有一定的智能服务的&#xff0c;但是一直都没有体现出多高的智能性&#xff0c;很多时候更像是‘人工智障’。 但是自从chatGpt3被大范围的营销和使用之后&#xff0c;人…

python常用基础知识

目录 &#xff08;1&#xff09;print函数 &#xff08;2&#xff09;注释 &#xff08;3&#xff09;input函数 &#xff08;4&#xff09;同时赋值和连续赋值 &#xff08;5&#xff09;type函数和id函数 &#xff08;6&#xff09;python赋值是地址赋值 &#xff08;…

Qt编译和使用freetype矢量字库方法

在之前讲过QT中利用freetype提取字库生成图片的方法&#xff1a; #QT利用freetype提取字库图片_qt freetype-CSDN博客文章浏览阅读1.2k次。这是某个项目中要用到的片段&#xff0c;结合上一篇文章#QT从字体名获取字库文件路径使用// 保存位图int SaveBitmapToFile(HBITMAP hBi…