Tornado简单使用

news2024/12/28 15:07:20

Tornado简单使用

1 介绍

Tornado 是一个基于Python的Web服务框架和 异步网络库,它最初由 FriendFeed 开发,后来被 Facebook 收购并开源,通过利用非阻塞网络 I/O, Tornado 可以承载成千上万的活动连接,完美的实现了 长连接、WebSockets, 和其他对于每一位用户来说需要长连接的程序.

# 官网地址
https://www.tornadoweb.org/en/stable/

# 多进程文档
https://www.tornadoweb.org/en/stable/httpserver.html#

# 安装Tornado
pip install tornado==6.3.3 -i https://pypi.tuna.tsinghua.edu.cn/simple

# 原生Websocket标准
https://websockets.spec.whatwg.org/

2 简单使用

helloword.py

import asyncio
import tornado

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

async def main():
    app = make_app()
    app.listen(8888)
    await asyncio.Event().wait()

if __name__ == "__main__":
    asyncio.run(main())

请求地址

# 地址
http://127.0.0.1:8888/

# 返回值
Hello, world

3 简单Web工程

3.1 Python代码

工程目录

在这里插入图片描述

base_web_handler.py

import logging

import tornado
from tornado.escape import json_decode, to_unicode


class BaseHandler(tornado.web.RequestHandler):

    # def set_default_headers(self):
    # 设置参数
    # pass

    def get_json_argument(self, name, default=None):
        # 解析参数
        args = {}
        try:
            args = json_decode(self.request.body)
        except Exception as e:
            logging.info("json is error")
            pass
        # 编码数据
        name = to_unicode(name)

        # 解析参数
        if name in args:
            return args[name]
        elif default is not None:
            return default
        else:
            # 通知参数异常
            raise tornado.web.MissingArgumentError(name)

message_handler.py

import tornado.websocket


class MessageWebSocket(tornado.websocket.WebSocketHandler):

    # 验证连接
    def check_origin(self, origin):
        # 用于验证跨域(cross-origin requests)
        print(origin)

        # 返回true才能连接,返回false不能连接
        return True

    def open(self):
        # 建立连接
        print("WebSocket opened")

    def on_message(self, message):
        print("Received message:", message)

        self.write_message("Received message:" + "zhonguodoe")
        pass

    def on_close(self):
        print("WebSocket closed")

form_handler.py

from config.base_web_handler import BaseHandler


class FormHandler(BaseHandler):

    def get(self):
        # 获取表单参数
        print(self.get_arguments("name"))
        print(self.get_argument("name"))

        print(self.get_body_arguments("name"))
        print(self.get_body_argument("name"))

        self.write("Hello, world")

json_handler.py



from config.base_web_handler import BaseHandler


class JsonHandler(BaseHandler):
    # post方法
    def post(self):
        # 获取body参数
        # 注意:Tornado本身没有将body解析json的方法,下面方法是自己封装的BaseHandler中构建的
        print(self.get_json_argument("data"))

        self.write("Hello, world")

sse_handler.py

import asyncio

from tornado import gen

from config.base_web_handler import BaseHandler


class SseHandler(BaseHandler):
    def set_default_headers(self):
        # 设置为事件驱动模式
        self.set_header('Content-Type', "text/event-stream")
        # 不使用缓存
        self.set_header('Content-Control', "no-cache")
        # 保持长连接
        self.set_header('Connection', "keep-alive")
        # 允许跨域
        self.set_header('Access-Control-Allow-Origin', "*")

    # 使用协程调度实现并发
    @gen.coroutine
    def get(self):
        # 使用生成器来发送数据流
        for i in range(3):
            self.write(self.build_message("test" + str(i)))
            yield asyncio.sleep(1)
            print("test1" + str(i))

            # 发送数据并在这里暂停,直到下一次生成器被迭代
            self.flush()

        # 数据流发送完毕后,调用finish结束请求
        self.finish()


    def build_message(sekf, message: str, event="message"):
        """
        构建消息
        :param message: 数据消息
        :param event: 事件,默认事件是“message”,可以根据自己的需求定制事件,对应前端的eventSource.addEventListener('message',()=>{}, false)中的message。
        :return:
        """
        head = "event:" + event + "\n" + "data:"
        tail = "\n\n"
        return head + message + tail

main.py

import asyncio

import tornado
from tornado.httpserver import HTTPServer
from tornado.netutil import bind_sockets

from route import make_app


# 单进程
async def main():
    app = make_app()
    app.listen(8881)
    await asyncio.Event().wait()

if __name__ == "__main__":
    asyncio.run(main())



"""

# 多进程,只有在多颗CPU上才能运行,不支持Windows
def main():
    sockets = bind_sockets(8888)
    tornado.process.fork_processes(0)

    async def post_fork_main():
        # 创建APP
        app = make_app()

        # 创建服务
        server = HTTPServer(app)
        server.add_sockets(sockets)
        await asyncio.Event().wait()

    asyncio.run(post_fork_main())


if __name__ == '__main__':
    main()
    
"""

route.py

import tornado

from socket_handler.message_handler import MessageWebSocket
from web_handler.form_handler import FormHandler
from web_handler.json_handler import JsonHandler
from web_handler.sse_handler import SseHandler


def make_app():
    return tornado.web.Application([
        # 验证基础表单
        (r"/form", FormHandler),
        (r"/json", JsonHandler),

        (r"/sse", SseHandler),

        # Websocket请求
        (r"/msg", MessageWebSocket),

    ])

3.2 前端代码

Vue3的SSE代码

<script setup lang="ts">
import { onBeforeUnmount} from 'vue'

defineProps<{ msg: string }>()


// 定义EventSource
let eventSource: any = null


// 建立连接
function createSseConnect(dataId: string) {
  if (window.EventSource) {
    // 创建连接
    eventSource = new EventSource('http://127.0.0.1:8881/sse');

    console.log("test");

    // 接收消息
    eventSource.onmessage = (event: MessageEvent) => {
      console.log(event)
      console.log("onmessage:" + dataId + ": " + event.data)
    };

    // // 也可以使用addEventListener实现自定义事件和默认message事件
    // eventSource.addEventListener('message', (event: MessageEvent)=> {
    //     console.log("message" + dataId + ": " + event.data);
    // }, false);


    // 打开连接
    eventSource.onopen = (event: Event) => {
      console.log("onopen:" + dataId + ": " + event)
    };

    // 连接出错时
    eventSource.onerror = (event: Event) => {
      console.log(event)
      console.log("onerror :" + dataId + ": " + event)
      eventSource.close();
    };

  } else {
    console.log("浏览器不支持SSE")
  }
}

// 组件销毁
onBeforeUnmount(() => {
  // 关闭EventSource
  if(eventSource != null){
    eventSource.close()
  }
})

</script>

<template>
  <h1>{{ msg }}</h1>

  <input type="button" value="发送消息" v-on:click="createSseConnect('1234')" />

</template>

<style scoped>
.read-the-docs {
  color: #888;
}
</style>

Html5的WebSocket

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <script type="text/javascript">
        function WebSocketTest() {
            if ("WebSocket" in window) {
                // 构建WebSocket
                var ws = new WebSocket("ws://localhost:8881/msg");

                ws.onopen = function () {
                    // Web Socket 已连接上,使用 send() 方法发送数据
                    ws.send("发送数据");
                    alert("数据发送中...");
                };

                ws.onmessage = function (evt) {
                    var received_msg = evt.data;
                    console.log(received_msg)
                    //   alert("数据已接收...");
                };

                ws.onclose = function () {
                    // 关闭 websocket
                    alert("连接已关闭...");
                };
            }else {
                // 浏览器不支持 WebSocket
                alert("您的浏览器不支持 WebSocket!");
            }
        }
    </script>

</head>

<body>

    <div id="sse">
        <a href="javascript:WebSocketTest()">运行 WebSocket</a>
    </div>

</body>

</html>

3.3 请求地址

# 表单请求
http://127.0.0.1:8888/form

在这里插入图片描述

# json请求
http://127.0.0.1:8888/json

在这里插入图片描述

# WebSocket请求
ws://127.0.0.1:8881/msg

在这里插入图片描述

# SSE请求
http://127.0.0.1:8881/sse

在这里插入图片描述

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

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

相关文章

基于SpringBoot的城镇保障性住房管理策略

3系统分析 3.1可行性分析 通过对本城镇保障性住房管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本城镇保障性住房管理系统采用SSM框架&#xff0c;JA…

【万字详解】如何在微信小程序的 Taro 框架中设置静态图片 assets/image 的 Base64 转换上限值

设置方法 mini 中提供了 imageUrlLoaderOption 和 postcss.url 。 其中&#xff1a; config.limit 和 imageUrlLoaderOption.limit 服务于 Taro 的 MiniWebpackModule.js &#xff0c; 值的写法要 &#xff08;&#xff09;KB * 1024。 config.maxSize 服务于 postcss-url 的…

[实战-11] FlinkSql 设置时区对TIMESTAMP和TIMESTAMP_LTZ的影响

table.local-time-zone table.local-time-zoneDataStream-to-Table Conversion&#xff08;拓展知识&#xff09;代码测试flinksql代码执行结果截图1. Asia/Shanghai 结果如下2. UTC结果如下 table.local-time-zone table.local-time-zone可用于设置flinksql的时区。 flink的内…

Bypassuac之白名单结合注册表方式

参考 Bypass UAC 原来这么简单 本章记录一下系统白名单文件结合注册表bypassuac&#xff0c;uac这个东西并不是Windows设置的防御机制而是相当于保护机制&#xff0c;只是用来控制用户行为的&#xff0c;弹个窗来提醒一下用户的行为&#xff0c;和直接的杀软是不一样的性质&am…

【力扣打卡系列】单调栈

坚持按题型打卡&刷&梳理力扣算法题系列&#xff0c;语言为go&#xff0c;Day20 单调栈 题目描述 解题思路 单调栈 后进先出 记录的数据加在最上面丢掉数据也先从最上面开始 单调性 记录t[i]之前会先把所有小于等于t[i]的数据丢掉&#xff0c;不可能出现上面大下面小的…

如何通过CDN加速提升电商网站双十一购物节用户体验

随着双十一购物节的到来&#xff0c;电商平台迎来了一年中流量的高峰。各大电商平台如天猫、京东和抖音等纷纷推出了全新的促销活动和玩法。在这场购物狂欢中&#xff0c;用户体验成为了电商网站能否脱颖而出的关键。而CDN&#xff08;内容分发网络&#xff09;加速服务&#x…

Linux信号_信号的产生

信号概念 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。 异步&#xff1a;在异步操作中&#xff0c;任务可以独立执行。一个任务的开始或完成不依赖于其他任务的状态。 同步&#xff1a;在同步操作中&#xff0c;任务之间的执行是相互依赖的。一个任务必须等待…

Docker学习—Docker核心概念总结

核心概念总结 容器&#xff1a;容器就是将应用运行所需的所有内容比如代码、运行时环境&#xff0c;进行打包和隔离。 容器和虚拟机的对比 虚拟机是在同一个硬件上虚拟化出多个操作系统&#xff08;OS&#xff09;实例。 容器是在操作系统上进行虚拟化&#xff0c;用于隔离…

51单片机教程(六)- LED流水灯

1 项目分析 基于点亮LED灯、LED灯闪烁&#xff0c;扩展到构成最简单、花样流水灯。 2 技术准备 1 流水灯硬件及原理图 流水灯是由多个LED灯组成的 2 C语言知识点 数组 数组声明&#xff1a;长度不可变 数据类型 数组名称[长度n] // 整数型默认为0&#xff0c;小数型默认…

供热的一些基础技术数据

1、应该了解的几个实用数据:(1)室内采暖达标温度182℃(2)建筑面积采暖热负荷 4060kcal/h㎡(4570W/㎡)(3)建筑面积采暖所需合理流量 2.53.5kg/h㎡(节能建筑12 kg/h㎡)(4)一次网严寒期外网总供、回水温度5570℃(5)热网的补水量应小于热网循环量的1%(6)1蒸吨的热量可供11.5 万平方…

【1个月速成Java】基于Android平台开发个人记账app学习日记——第7天,申请阿里云SMS短信服务SDK

系列专栏链接如下&#xff0c;方便跟进&#xff1a; https://blog.csdn.net/weixin_62588253/category_12821860.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12821860&sharereferPC&sharesourceweixin_62588253&sharefromfrom_link 同时篇幅…

A02、JVM性能监测调优

1、JVM内存模型 1.1、介绍 JVM 自动内存分配管理机制的好处很多&#xff0c;但实则是把双刃剑。这个机制在提升 Java 开发效率的同时&#xff0c;也容易使 Java 开发人员过度依赖于自动化&#xff0c;弱化对内存的管理能力&#xff0c;这样系统就很容易发生 JVM 的堆内存异常&…

钉钉调试微应用整理2

第一步 新建应用 钉钉开放平台](https://open-dev.dingtalk.com/) 去新增应用 第二步 配置应用信息 把本地代码运行起来&#xff0c;并设置本地地址 第三步 在本地代码添加调试命令 这里有2中添加方式 哪一种都可以 方式一&#xff1a; index.html页面中 <!DOCTYPE h…

《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列

《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列 《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列分配给套接字的IP地址和端口号网络地址网络地址分类和主机地址边界用于区分套接字的端口号数据传输过程示例 地址信息的表示表示IPv4…

飞牛fnOs内网穿透-使用Lucky实现ipv6动态解析+HTTPS访问NAS服务

&#x1f9ed;Lucky官方介绍 Lucky最初是作为一个小工具&#xff0c;由开发者为自己的个人使用而开发&#xff0c;用于替代socat&#xff0c;在小米路由AX6000官方系统上实现公网IPv6转内网IPv4的功能。Lucky的设计始终致力于让更多的Linux嵌入式设备运行&#xff0c;以实现或…

《安富莱嵌入式周报》第345期:开源蓝牙游戏手柄,USB3.0 HUB带电压电流测量,LCR电桥前端模拟,开源微型赛车,RF信号扫描仪,开源无线电收发器

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 本周更新一期视频教程 第5期&#xff1a;RTX5/FreeRTOS全家桶源码工程综合实战模板集成CANopen组件&#xff08;2024-1…

微服务中常用分布式锁原理及执行流程

1.什么是分布式锁 分布式锁是一种在分布式系统环境下实现的锁机制&#xff0c;它主要用于解决&#xff0c;多个分布式节点之间对共享资源的互斥访问问题&#xff0c;确保在分布式系统中&#xff0c;即使存在有多个不同节点上的进程或线程&#xff0c;同一时刻也只有一个节点可…

三:LoadBalancer负载均衡服务调用

LoadBalancer负载均衡服务调用 1.LB负载均衡(Load Balance)是什么2.loadbalancer本地负载均衡客户端 与 Nginx服务端负载均衡区别3.实现loadbalancer负载均衡实例3-1.首先应模拟启动多个服务提供者应用实例&#xff1a;3-2.在服务消费项目引入LoadBalancer3-3&#xff1a;测试用…

简单入门Git

Git作用 Git简介 作用&#xff1a;版本控制多人协作 集中式 典型代表&#xff1a;SVN 特点&#xff1a;所有的版本库都存在中央服务器&#xff0c;本地备份动作必须依赖中央服务器&#xff0c;如果一旦服务器挂掉&#xff0c;或者网络状况不好&#xff0c;没法提交版本。…

解决echarts桑基图为0时tooltip不显示的问题

关键代码 formatter: function (params) {console.log("params",params)if (params.value 0) {// 如果值为0&#xff0c;返回空字符串&#xff0c;不显示任何内容return params.name : params.value;// return ;} else {// 否则返回标准的格式化信息return par…