Day 22 Flask-SocketIO

上一篇讲完了 Flask 的本体,这篇开始就要开始讲 Flask 的插件了。Flask 从初始版本(2010/04/01)发布以来,已经过去了 10 年左右,许多人为了能够更加快速的开发,贡献了需多方便使用的插件。而这篇要介绍第一个插件就是 — Flask-SocketIO。

讲到现在有没有发现 HTTP 协议的模式基本上是 Client 打一下回应一下,再打一下再回应一下,而现在如果 Server 端需要主动传资讯给 Client,就必须等使用者下一次打的时候,包再回应里面再回传给 Client。

早期各种网路应用还不发达的时候,也许并没有问题,但是现在各种各样的应用出来之後,这样的模式就有点不足了,所以就有了 WebSocket 这个东西,而 WebSocket 相比 HTTP 协议,WebSocket 有着以下的优点:

  1. 支援双向通讯(超重要,我就是要讲它)。
  2. 建立连线後,WebSocket 客户端、服务端资料交换时,资料包标头较小。
  3. 支援扩充套件。

不过 WebSocket 只是协议,需要有一个程序去实作它,并且作为套件供其他程序使用,而且前後端都需要有个程序去实作,否则无法达成双向通讯。在前端处理这些东西的通常都是 JavaScript ,所以 JavaScript 中 WebSocket 的套件叫做 Socket.IO ,而在後端的 Flask 中也有相对应的套件,而那个套件就是这篇的主题 — Flask-SocketIO。

总而言之

WebSocket -> 协议
Socket.IO -> JavaScript 的前端实作
Flask-SocketIO -> Flask 框架的後端实作

大概就酱

Flask-SocketIO 使用

首先,因为是插件,所以并没有包含在 Flask 里面,需要另外安装。当然还是使用我们熟悉的 pip 来安装啦,不过除了安装 Flask-SocketIO 以外,还要安装 Flask-SocketIO 依赖的非同步服务 eventlet。

$ pipenv install flask-socketio eventlet

既然说到了安装,那就先来说一下後端如何使用好了(因为前端的话只要使用 JavaScript 然後透过 CDN 导入就可以了),假设现在要做一个超简单的聊天室(终於不是拿前面的那坨来改了,记得 pipenv install flask 喔),架构长这样(虽然不是拿前面那坨改,但是还是有几个可以复制过来沿用):

ithome_chatroom
├── templates
│   └── index.html  # 聊天室首页
├── app.py  # 主要的档案(很烂的形容我知道,我就不会形容啊)
├── configs.py  # 设定档
├── Pipfile  # 不管它,建立虚拟环境时自己会出现
└── Pipfile.lock  # 不管它,安装套件时自己会出现

首先当然是做好聊天室後端啦,後端当然是写在 app.py 里面。

app.py

from flask import Flask, render_template
from flask_socketio import SocketIO  # 加上这行

import configs


app = Flask(__name__)
app.config.from_object(configs)

socketio = SocketIO(app)  # 加上这行


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


@socketio.on('send')
def chat(data):
    socketio.emit('get', data)


@socketio.on('test')
def test():
    socketio.send("test")


if __name__ == "__main__":
    socketio.run(app)

处理好後端之後呢,接着当然就是前端啦,不过前端有点特殊,刚刚前面讲过前端需要有个程序来处理,不过这个架构上看起来并没有前端的处理程序阿?那是因为前端的处理程序可以在渲染前端时,透过 CDN 导入後在执行,而只需要在 .html 档里面加上一句就可以了(不是我偷懒不讲啦,只是弄个小小的实验而已没必要搞得这麽复杂啦)。

那要怎麽找 CDN 来导入呢?可以从下面两个(Socket.IO 是必要的,JQuery 可以不必,只是因为我喜欢用 JQuery 而已,没办法,JavaScript 语法太长了)连结进去,找到随便一个版本(我推荐是用红色背景的那个),然後找到 </> 这样的案件,点下去就复制好了。

Socket.IO 的 CDN

JQuery 的 CDN

复制好了之後,来到 index.html 贴上,再加上几行就 OK 了。

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>WebSocket test</title>
    
    <!-- JQuery 的 CDN 连结 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
        integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
        
    <!-- Socket.IO 的 CDN 连结 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js"
        integrity="sha512-WL6WGKMPBiM9PnHRYIn5YEtq0Z8XP4fkVb4qy7PP4vhmYQErJ/dySyXuFIMDf1eEYCXCrQrMJfkNwKc9gsjTjA=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    <!-- Socket.IO 的使用 -->
    <script type="text/javascript" charset="utf-8">
        $(document).ready(function () {
            // Socket.IO Start connect
            var socket = io.connect();
            
            
            // Socket.IO send message
            $("#send").click(function (e) {
                // Send message
                socket.emit('send', $('#message').val())
                // Clear input field
                $('#message').val('')
            });
            
            // Socket.IO get message
            socket.on('get', function (data) {
                $('#chat_content').append('<p>I say: ' + data + '</p>');
            });
            
            // Socket.IO get test
            socket.on("message", function (data) {
                $('#chat_content').append('<p>System : ' + data + '</p>');
            });
            
            // Socket.IO send test
            $("#test").click(function (e) {
                socket.emit('test')
            });
        });
    </script>
</head>


<body>
    <h1>Hello</h1>
    <h2>WebSocket test</h2>
    <form>
        <fieldset>
            <legend>Message</legend>
            <input type="text" id="message" name="message" />
            <input type="button" id="send" value="Send" />
            <input type="button" id="test" value="Test" />
        </fieldset>
    </form>
    <hr />
    <div id='chat_content'></div>
</body>
</html>

这样子输入完就可以了,简单来说 sendemit 可以传送事件,其中send 是传送未命名事件;而 emit 是传送命名事件。on 则是监听有无事件发生。

那就来看执行後会发生什麽事吧。

看起来没有发生什麽对吧,再 input 输入一点东西後按下 Send 看看。

如果再按下旁边的 Test 呢?

是不是没有看出来哪里厉害对吧,同时开两个分页再重复上面的操作後你就懂了。

那麽就大概这样,WebSocket 还有很多可以说的,但是如果全部塞在同一篇的话就太多了,而且我後面还有其他插件要说,所以 WebSocket 就先介绍到这里。

大家掰~掰~


<<:  [DAY 22]纠团通知功能(2/3)

>>:  Day22 - Shioaji X Backtesting -双均线策略

Day02: Hello TypeScript! 环境安装起来 + 牛刀小试~

Q: 同事说自己的 C++ 能力是世界第一,怎麽样可以让他意识到自己没那麽厉害? A: 实不相瞒,...

验证资料/产生测试资料/表格显示 - day05

储存前,验证资料正确性 当使用者输入资料後需要验证资料正确性,并提示给使用者。在VoK要做到这点非常...

Day 24 开发者福音无服务器运算

随着资讯技术普及与推陈布新,基础设施及服务(IaaS)、平台即服务(PaaS)、软件即服务(Saa...

D-25-回圈 loop ? foreach ? while

回圈 loop 昨天小光更进一步的认识了逻辑判断式,也开始自己开发了一个心情显示器,不过如果要表现1...

Day.4 针对使用者做管理 - 权限管理&资安 (Power)

在资料库管理上,root 相当於拥有所有权限的最大管理者,针对不同使用者规划给予相应的权限是很重要的...