python tornado websocket + luyui js实现前端上传py文件→后端运行→前端显示运行结果

python tornado websocket + luyui js实现前端上传py文件→后端运行→前端显示运行结果

  • tornado框架
    tornado:python的web框架

  • Websocket简介
    WebSocket是一种网络通信协议,与Http协议不同的是,WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。

  • python tornado实现Websocket
    需求:前端使用layui上传xxx.py文件,后端接收后调用popen()函数执行命令行语句 “python xxx.py”,编译运行结果返回给前端,前端界面显示运行结果

后端代码(python2.7):

# -*- coding: utf-8 -*-
import os
import subprocess

from tornado.escape import json_encode
from tornado.websocket import WebSocketHandler
from tornado.web import RequestHandler
from tornado import ioloop,httpserver,web
from tornado.options import define,options

define('port',default='6666',help='run port',type=int)
define('runserver',default=True,help='run server',type=bool)
#websocket实现类
class WSHandler(WebSocketHandler):
    users=set()
    def open(self):
        WSHandler.users.add(self)
        print('connected')
    def on_message(self, message):
        print(self.request.remote_ip,message)
        for u in self.users:
            u.write_message('[%s]:%s'%(self.request.remote_ip,message))
    def on_close(self):
        print('8888')
        WSHandler.users.remove(self)

    @classmethod
    def send_demand_updates(cls, message):
        # 使用@classmethod可以使类方法在调用的时候不用进行实例化
        # 给所有用户推送消息(此处可以根据需要,修改为给指定用户进行推送消息)
        for user in cls.users:
            user.write_message(message)
#主入口
class MainHandler(RequestHandler):
    def get(self):
        self.render('infopage.html')
        pass
#接收前端文件上传的类
class FileUpload(RequestHandler):
    def post(self,*args, **kwargs):
        #指定文件存储路径(此处使用了绝对路径,拷贝后注意修改)
        upload_path = os.path.join(os.path.dirname(__file__), 'D://SoftwareDevelope//template_test3.0//pyfile')
        #request接收文件
        file_metas = self.request.files
        if file_metas:
            print upload_path
            print file_metas
            '''
            输出结果{'file': [{'body': 'print "nihao"', 'content_type': u'text/plain', 'filename': 'test2.py'}]}
            file_metas是个字典,key值只有一个file,value值是一个列表,列表只有一个元素,且该元素是个字典类型
            '''
            # 获取文件名
            filename = file_metas.get('file')[0].get('filename')
            print filename
            # 获取文件内容
            filecontent = file_metas.get('file')[0].get('body')
            # 将文件内容写入本地同名py文件
            filepath = os.path.join(upload_path, filename)
            with open(filepath, 'wb') as up:  # 有些文件需要已二进制的形式存储,实际中可以更改
                up.write(filecontent)
            # 编译执行上一步接收到的并存于本地的同名py文件
            cmd = "python " + upload_path + '//' + filename
            #使用subprocess的Popen函数运行cmd命令语句,此处是使用python来编译.py文件
            re = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
            out = re.stdout.readlines()
            #从数据流逐行获取数据,发送至前端
            for line in out:
                data = line.strip()
                print data
                #调用WSHandler的send_demand_updates(message)方法向前端传送运行结果
                WSHandler.send_demand_updates(data)
            result = {
                "result": 'success',
                'status': True,
                'code': 200
            }
            self.write(json_encode(result))
        else:
            result = {
                "result": 'error',
                'status': False,
                'code': 404
            }
            self.write(json_encode(result))
#url
handlers=[
    (r'/ws',WSHandler),
    (r'/',MainHandler),
    (r'/fileupload',FileUpload),
]

if __name__ == '__main__':
	#指定html模板路径及js,css静态文件路径
    setting = dict(
        template_path=os.path.join(os.path.dirname(__file__), "templates"),
        static_path=os.path.join(os.path.dirname(__file__), "static"),
    )
    options.parse_command_line()
    if options.runserver:
        app = web.Application(handlers=handlers, debug=True,**setting)
        httpser=httpserver.HTTPServer(app)
        httpser.listen(options.port)
        print('running...')
        ioloop.IOLoop.instance().start()

前端代码(layui):

<!--$def with(user_name)-->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>模板测试</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="{{static_url('css/layui.css')}}" media="all">
    <link rel="stylesheet" href="{{static_url('css/addstyle.css')}}" media="all">
    <script type="text/javascript" src="{{static_url('layui.js')}}"></script>
    <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
    <script src="http://cdn.static.runoob.com/libs/jquery/1.9.0/jquery.js"></script>
    <style>
        html {
            height: 100%;
        / / 让html的高度等于屏幕
        }
        body {
            height: 100%;
            margin: 0;
        }
    </style>
</head>

<body style="background-color:rgba(244,244,244,1)">
<div style="height: 100%">
    <div style="height: 15%">
        <br>
        <br>
        <div>
            <div class="layui-col-md11">
                <input type="text" name="pyfile" id="pyfile" placeholder="点击选择模板文件" class="layui-input">
            </div>

            <div class="layui-col-md1">
                <button type="button" class="layui-btn" id='fileupload' onclick="fileupload()">
                    <i class="layui-icon">&#xe67c;</i>确认上传
                </button>
            </div>
        </div>

    </div>

    <div class="layui-col-md12" style="height: 85%">
        <div class="layui-card" style="height: 100%">
            <div class="layui-card-header">
                <div class="layui-col-md12">
                    日志显示
                </div>
            </div>
            <div class="layui-card-body" id="scroll" style="height: 85%; overflow-y:scroll">
                <ul class="ul" id="ul">
                    <li>这是写死的测试行</li>
                    <!--<li>shishijiushishi</li>-->
                </ul>
            </div>
        </div>
    </div>
</div>
</body>
<!--连接websocket-->
<script>
	//WebSocke核心,onmessage接收和发送数据,此处是接收后端返回的运行结果,添加到无须列表,并将无序列表动态添加到html
    var ws = new WebSocket('ws://127.0.0.1:6666/ws');
    ws.onopen = function () {
        console.log('连接成功');
    };
    ws.onmessage = function (mes) {
        var parentbody = document.getElementById("ul");
        var br = document.createElement("div");
        br.innerHTML = "<li>" + mes.data + "</li>";
        parentbody.appendChild(br);
        var showContent = document.getElementById("scroll");
        showContent.scrollTop = showContent.scrollHeight;

        console.log(mes.data);
        console.log('接收/发送成功');
    };
    ws.onclose = function () {
        console.log('连接已断开');
    };
</script>

<!--模板文件上传-->
<script>
    // 每次点击上传先清空原有记录
    function fileupload() {
        document.getElementById('ul').innerHTML = "";
    }
    //layui上传文件
    layui.use('upload', function () {
        var upload = layui.upload;
        //执行实例
        var uploadInst = upload.render({
            elem: '#pyfile' //绑定元素
            , url: '/fileupload' //上传接口
            , accept: 'file'
            , exts: 'py'
            , auto: false
            , area: ['1800px', '1350px']
            , bindAction: '#fileupload'
            , choose: function (obj) {
                obj.preview(function (index, file, result) {
                    layui.jquery('#pyfile').val(file.name);
                })
            }
            , data: {
                user_name: "user_name",
            }

            , error: function () {
                console.log("error occur");
            }
            , success: function () {
                console.log("success");
            }
        });
    });
</script>
</html>
  • 运行示例
    try.py中写
    在这里插入图片描述
    前端上传改py文件,显示执行结果
    在这里插入图片描述
    后记:这个是爬虫平台的一个序曲,本来这个功能是用来运行模板的日志的,改成python网页运行器了,只不过是需要上传写好的py文件,O(∩_∩)O哈哈~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值