1. 程式人生 > >Web端作業控制系統簡易實現

Web端作業控制系統簡易實現

服務一覽

如上圖所示,這篇文章基於此圖進行實現。其功能就是,可以在WEB端對後臺的一些服務進行控制。最初的想法來自於近期將要做的畢設專案。

因為是爬蟲程式,所以有可能會長期跑一些指令碼,又不能隨時帶著電腦(阿里雲APP上倒是有一個ssh工具,很方便),所以做成一個web服務,這樣直接用瀏覽器就可以簡單的完成一些操作了。

專案結構

因為類似的服務,有點繞。所以簡單的分下層,理解起來會更容易點。其實說白了,就是一個帶有了WEB服務的IPC實現。具體的流程為:
客戶端通過web請求,呼叫到服務指令碼執行對應的訊號處理,完成對目標指令碼的控制

下面展示下目錄結構,方便理解:

[email protected]
:~/control$ tree . ├── api.py # flask 服務相關 ├── control.sh # 訊號處理相關 ├── father.log # 日誌檔案 ├── get-process-status.sh # 指令碼執行狀態相關 ├── jobs.list # 可操作的服務列表 ├── log # 日誌檔案,測試用 ├── py.log # 日誌檔案,測試用 ├── scripts # 存放服務指令碼的目錄 │ ├── testforbash.sh # 測試bash指令碼 │ ├── testforphp.php
# 測試PHP指令碼 │ └── testforpy.py # 測試Python指令碼 ├── start-program.py # 被control.sh呼叫,根據拓展名找到對應直譯器並開啟服務 ├── static # flask 預設靜態檔案目錄 │ ├── css │ │ ├── detail.css │ │ └── index.css │ ├── imgs │ │ ├── background.jpg │ │ ├── favicon.ico │ │ └── header.jpg │ └── js │ ├── detail.js
│ ├── index.js │ └── jquery-2.2.4.min.js └── templates # flask 預設模板目錄 └── index.html

程式碼段

下面按照上述目錄結構,貼一下程式碼。程式碼都很簡單,瞭解了流程之後也就不難理解了。這裡不再做過多的贅述。

api.py

developer@aliyun:~/control$ cat api.py
#!/usr/bin python
# coding: utf8
import sys
reload(sys)
sys.setdefaultencoding("utf8")
import os
import commands
import json
from flask import Flask,request,render_template
# for easy usage, just all in. begin
# 獲取可以控制的指令碼列表
def get_programs():
    with open("./jobs.list", "r") as file:
        programs = file.readlines()
        file.close()
    return [line.strip("\n") for line in programs]
# 根據指令碼名稱獲取當前指令碼的執行狀態
def get_status_by_name(program=""):
    cmd = "bash get-process-status.sh {}".format(program)
    status, output = commands.getstatusoutput(cmd)
    return status, output

# 控制指令碼執行,暫停,或者殺死
def control_program(program="", command=""):
    cmd = "bash control.sh {} {} &".format(program, command)
    return os.system(cmd)

# end
app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/program")
def program():
    res = {"data":[], "code":-1}
    try:
        programs = get_programs()
        res = {"data": programs, "code":0}
    except exception as e:
        res = {"data": e, "code":-1}
    return json.dumps(res)
@app.route("/status", methods=["POST", "GET"])
def status():
    params = {}
    if request.method == "POST":
        params = request.form.to_dict()
    elif request.method == "GET":
        params = request.args.to_dict()
    else:
        params = {}
    program = params.get("program", "")
    status = get_status_by_name(program)
    return json.dumps({"data":status})

@app.route("/control", methods=["POST", "GET"])
def control():
    params = {}
    if request.method == "POST":
        params = request.form.to_dict()
    elif request.method == "GET":
        params = request.args.to_dict()
    else:
        pass
    program = params.get("program")
    command = params.get("command")
    print program, "==", command
    res = control_program(program, command)
    return render_template("index.html")

if __name__ == "__main__":
    #print get_programs()
    #program = "/home/developer/control/scripts/testforphp.php"
    #print get_status_by_name(program)
    #print control_program(program, "start")
    #print get_status_by_name(program)
    app.run(host="0.0.0.0", port=9999, debug=True)

control.sh

[email protected]:~/control$ cat control.sh 
#!/usr/bin bash
# 獲取$1 內容對應的程序id
echo "命令為" $1
PID=$(ps aux | grep -v grep | grep $1 | awk '{print $2}'| head -1)
echo "捕獲的程序號為" $PID "具體的命令為" $2
# 根據$2引數來控制程序
if [[ $2 == "stop" ]];then
    echo "暫停" $1
    kill -SIGSTOP $PID
elif [[ $2 == "resume" ]];then
    echo "繼續" $1
    kill -SIGCONT $PID
elif [[ $2 == "kill" ]];then
    echo "終止" $PID
    kill -9 $PID
elif [[ $2 == "start" ]];then
    #echo "可以交給python指令碼根據對應的拓展名來開啟對應的服務"
    echo "正在開啟指令碼..."
    /usr/bin/python /home/developer/control/start-program.py $1 > /home/developer/control/father.log
else
    echo "暫不支援的操作~"
fi
echo "OVER!"

get-process-status.sh

[email protected]:~/control$ cat get-process-status.sh 
#!/usr/bin bash

PROGRAM=$1
STATUS=$(ps aux | grep -v grep| grep $PROGRAM | head -1 | awk '{print $8}')
echo $STATUS
exit
if [[ $STATUS == "T"  ]];then
    echo $PROGRAM is Stopping...
elif [[ $STATUS == "S"  ]];then
    echo $PROGRAM is S
elif [[ $STATUS == "R" ]];then
    echo $PROGRAM is Running.
else
    echo $PROGRAM is $STATUS
fi

jobs.list

developer@aliyun:~/control$ cat jobs.list 
/home/developer/control/scripts/testforpy.py
/home/developer/control/script/testforbash.sh
/home/developer/control/scripts/testforphp.php

scripts

這個目錄用於拓展服務的列表,需要新增新的可控指令碼的話,只需要在這個資料夾和jobs.list下進行新增即可。

testforbash.sh

[email protected]:~/control$ cat scripts/testforbash.sh 
#!/usr/bin bash
for ((i=1; i<10;i++))
do
    echo $i "carried."
    sleep 3
done

testforphp.php

developer@aliyun:~/control$ cat scripts/testforphp.php 
<?php

while(true) {
    $date = date("Y-m-d H:i:s");
    echo "PHP 當前時間是[{$date}].\n";
    sleep(10);
}

testforpy.py

developer@aliyun:~/control$ cat scripts/testforpy.py 
#!/usr/bin python
#coding: utf8
import sys
import time
reload(sys)
sys.setdefaultencoding("utf8")
index = 0
while True:
    with open("/home/developer/control/py.log", "a") as file:
        content = str("current time is: "+str(time.ctime())+"!\n")
        file.write(content)
        time.sleep(10)
        index+=1
        if index==10:
            break
        file.close()

start-program.py

developer@aliyun:~/control$ cat start-program.py 
#!/usr/bin python
#coding: utf8
import sys
reload(sys)
sys.setdefaultencoding("utf8")
import os
# 也可以使用subprocess庫,這樣效果貌似會更好
path = str(sys.argv[1])
print(path)
# 預設使用最後一個拓展名
extension = path.split(".")[-1]
# 根據拓展名找到對應的處理器
mapping = {
        "php": "php",
        "py": "python",
        "sh": "bash"
        }
exts = ['php', 'py', 'sh']
print("extension is: " + extension)
print("commander is:" + mapping.get(extension))
if extension in exts:
    cmd = "{} {}  >> log &".format(mapping.get(extension), path)
    print(cmd)
    os.system(cmd)
else:
    print("不支援的控制指令碼")

index.js

[email protected]:~/control$ cat static/js/index.js 
$(document).ready(function(){
    loading_data_for_selector($("#programs"));
    get_program_status($("#programs"), $("#previewer"));
    //commit_command($("#btn_click"), $("#programs"), $("#command"))
});


function commit_command(btn, programs, commander) {
    btn.click(function(){
        var program = "";
        var command = "";
        programs.change(function(){
            program = $(this).children("option:selected").val();
        });
        commander.change(function(){
            command = $(this).children("option:selected").val();
        });
        console.log(program+"<>"+command)
        $.ajax({
            url: "/control",
            method: "POST",
            dataType: "JSON",
            data: {program: program, command: command},
            success: function(res) {
                console.log(res);
            },
            error: function(err) {
                console.log(err);
            }
        });
    });
}

function loading_data_for_selector(obj){
    $.ajax({
        url: "/program",
        method: "GET",
        dataType: "JSON",
        success: function(res) {
            console.log(res);
            var data = res.data;
            for(var index=0; index<data.length; index++) {
                var child = "<option value='"+data[index]+"'>"+data[index]+"</value>";
                obj.append(child);
            }
        },
        error: function(err) {
            console.log(err);
        }
    });
}

/**
 * 當selector的選中值發生變化的時候,就會觸發對應的請求,用於及時將
 * 指令碼的執行狀態顯示到頁面上。
 */
function get_program_status(obj, previewer) {
    obj.change(function(){
        previewer.children().remove();
        var value = $(this).children("option:selected").val();
        $.ajax({
            url: "/status",
            method: "POST",
            dataType: "JSON",
            data: {program: value},
            success: function(res) {
                console.log(res);
                var data = res.data[1];
                var child = "<p><code>"+value+"</code>的執行狀態為"+data+"</p>";
                previewer.append(child);
            },
            error: function(err){
                console.log(err);
            }
        });
    });

index.html

[email protected]:~/control$ cat templates/index.html 
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>web端作業控制系統</title>
    <script type="text/javascript" src="/static/js/jquery-2.2.4.min.js"></script>
    <script type="text/javascript" src="/static/js/index.js"></script>
    <link rel="stylesheet" type="text/css" href="/static/css/index.css">
</head>
<body>
<div class="container">
    <div class="operator">
        <form action="/control" method="POST">
        <fieldset>
            <legend>填寫相關操作</legend>
            <select id="programs" name="program"></select>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <select id="command" name="command">
                <option value="start">開啟</option>
                <option value="stop">暫停</option>
                <option value="resume">繼續</option>
                <option value="kill">殺死</option>
            </select>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <input type="submit" id="btn_click" name="" value="提交">
        </fieldset>
    </form>
    </div>
    <div id="previewer" ="preview">

    </div>
</div>
</body>
</html>

到此,核心的檔案都已經羅列完畢了。雖然功能上沒什麼問題了,但是原生的頁面看起來確實不能讓人有賞心悅目的感覺。有興趣的話可以在此基礎上進行優化,寫一個更好看的頁面。

最終效果

開啟web服務

開啟web服務

檢視可控指令碼以及可用操作

檢視有哪些指令碼可被控制

在web頁面開啟一個測試的服務指令碼

開啟一個測試服務

在web頁面暫停一個測試服務指令碼

在web頁面暫停一個正在執行的指令碼

確認指令碼真的是暫停了。
實際驗證,指令碼真的是被暫停住了

繼續之前暫停了的服務

繼續之前暫停了的服務

終止一個服務

終止一個服務

下拉框選中後會出現當前指令碼的服務狀態

下拉框選中事件下的指令碼狀態更新

總結

到此,這個在web頁面控制服務行為的需求,馬馬虎虎算是做完了。但是不得不說,介面有點難看。在完成這個小工具的過程中,也算是遇到了各種各樣的坑。比如:

  • python檔案寫操作鎖沒釋放的
  • Bashsh某些命令不相容的
  • flask請求引數一致性保證的問題

等等吧。

雖然看起來這個小工具,用到的語言特別亂,也特別雜,但大部分程式碼都是很簡單的。從最上面的那張圖入手,相信理解起來會更容易一點吧。

相關推薦

Web作業控制系統簡易實現

如上圖所示,這篇文章基於此圖進行實現。其功能就是,可以在WEB端對後臺的一些服務進行控制。最初的想法來自於近期將要做的畢設專案。 因為是爬蟲程式,所以有可能會長期跑一些指令碼,又不能隨時帶著電腦(阿里雲APP上倒是有一個ssh工具,很方便),所以做成

吳裕雄 人工智能 java、javascript、HTML、python、oracle ——智能醫療系統WEB代碼簡潔版實現

list ret utf-8 init quest name viewport auth this <!DOCTYPE html> <!-- To change this license header, choose License Headers

基於Web高校宿舍選擇系統實現

權限系統 高並發 客戶 處理 權限 過程 邏輯 用戶中心 實現 為了講解如何實現該選擇系統,我講從如下角度拆分解析整個系統的實現過程,帶大家由淺入深的了解一個網站的功能是如何一步一步添加的 高校宿舍選擇系統的實現:業務邏輯以及要求分析 高校宿舍選擇系統的實現:邏輯分析與表

web工單系統登入狀態同步

需求:使用者訪問第三方公告時,如果當前處於登入狀態,需要第三方公告平臺保持登入狀態 方案:查詢第三方公告平臺是否提供相關介面,(除特殊情況下,是一定會有的),呼叫第三方平臺介面,拼接引數傳入使用者名稱,傳入郵箱,加密token,第三方解析請求引數完成,狀態同步以及url跳轉 介面請求方式

web專案 ios系統 click事件無響應

新專案為web專案  在ios系統上 有些click事件無反應  由於時間問題 沒有辦法呼叫fastclick外掛 或者 touchstart 來控制了.  經過查閱發現 可以在點選事件的元素上 加個style 就可解決  style="cursor:pointer"  

Android實現登入功能,Android與伺服器資料互動,使用tomcat、mysql實現登入的demo程式,web和android均可實現登入

1.使用到的開發工具為:Eclipse(Java EE),Android Studio,MYSQL 5.7.21;2.首先在MYSQL資料庫建表,我這裡使用的資料庫視覺化操作軟體為:navicat premium:如圖:這裡你可以取自己喜歡的資料庫名字,但是為了方便起見,我建

RPG遊戲《黑暗之光》流程介紹與程式碼分析之(三):角色控制系統實現

第三章:角色控制本篇部落格主要對人物移動及其相關操作進行分析,主要包括主角以及鏡頭的移動。在遊戲介面中,我們使用Camera作為視角。為了方便之後判斷當前tag,我們新建一個Tag指令碼,存入一些tag資訊,之後呼叫就不容易出錯using UnityEngine; using

基於WEB的網路遠端作業處理系統之使用者介面的設計與實現,java設計與開發

**基於WEB的網路遠端作業處理系統之使用者介面的設計與實現,java設計與開發** 基於WEB的網路遠端作業處理系統之使用者介面的設計與實現mysql資料庫建立語句 基於WEB的網路遠端作業處理系統之使用者介面的設計與實現oracle資料庫建立語句 基於WEB的網路遠端

《物聯網框架ServerSuperIO教程》-22.Web對傳感器實時監測與控制。附:v3.6.8版本,支持WebSocket

實時數據 title bmp 角色 1.4 增加 str 通訊 git 1.ServerSuperIO v3.6.8更新內容 1.1 增加WebSocket服務端功能,支持自控模式、並發模式、單例模式,不支持輪詢模式1.2 接收數據緩存與現有的IO實例分離。1.3 優化代

進程(WINAPI),遍歷並查找樹狀的進程信息,實現控制系統進程

ces pop size blog ext 快照 -a 查找 printf #include <TlHelp32.h> //檢索系統全部進程 void showall() { PROCESSENTRY32 pe32 = {0}; pe32.dwSiz

移動 Web 頁 input 控制軟鍵盤

utm 填寫信息 web前端 忽略 瀏覽器中 cnblogs click 折騰 quest 從交互層面上來講,完成一個功能(獲得想要的信息)的過程稱之為用戶路徑。用戶路徑越長,完成功能的復雜度就越高,用戶體驗也就越差。因此當打開一個需要用戶填寫信息的表單界面時,為了提高可用

Java 消息推送------GoEasy實現服務推送和web推送

subscribe rip world 查詢 start easy 需要 註冊 註意 項目中需要消息推送,又想較低開發成本,具體需求:角色用戶在後臺管理頁面發布一個消息,所有用這個系統的用戶無論在哪個頁面都能及時收到他發布的消息,後來我在網上查詢到了一個第三方的免費推送服務

H5與web如何用localStorage實現歷史紀錄?

line -a itl 輸入 left console otto 添加 實現 1.使用jq完成localStorage實現歷史紀錄版。     代碼如下: <!DOCTYPE html> <html> <head lang="en"

作業二 分布式版本控制系統Git的安裝與使用

left -- 並排 ssh d+ 個人 sta 命令顯示 單行 作業的要求來自於:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2097 第一步:配置用戶和郵箱

第二次作業:分布式版本控制系統Git的安裝與使用

tty tps ssh-key 第二次作業 版本信息 公鑰 mail d+ data- 作業的要求來自於:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2097 遠程倉庫的地址:https://github.

作業二:分布式版本控制系統Git的安裝與使用

練習 倉庫 用戶名 本地倉庫 nbsp lin -m 版本管理 版本控制 作業要求來自於:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2097 1.下載安裝配置用戶名和郵箱。 (1)下載安裝Git

第二次作業---分布式版本控制系統Git的安裝與使用

單行 adb 工作 con set 修改用戶名 diff 下載安裝 建立 作業的要求來自於:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2097 遠程倉庫的地址:https://github.com/Ing

第二次作業——分布式版本控制系統Git的安裝與使用

版本 分享 home 二次 圖片 cat 查看當前目錄 Git+http 檢查 作業要求來自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2097 遠程倉庫地址是:https://github.com/sh

分布式版本控制系統Git的安裝與使用 第二次作業

添加 font image git bubuko 提交 技術分享 倉庫 init (本次作業要求來自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103) 一、安裝Git bash軟件和安裝notepad

MATLAB實現控制系統的根軌跡分析

要點 1、零極點圖繪製 2、根軌跡圖繪製 3、 rlocfind()函式 4、 sgrid()函式 實操 3-1 k=1; num=[1 2 2]; den=conv([1,0],conv([1,4],conv([1,6],[1,4,4]))); [p,z]=