Flask-websocket實現聊天功能


群聊無昵稱

原生js代碼

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>群聊</title>
</head>
<body>
<p>
    <input type="text" id="content">
    <button onclick="send_msg()">發送</button> <!--給按鈕綁定點擊事件-->
</p>

<div id="chat_list">

</div>
</body>
<script type="application/javascript">
  var ws = new WebSocket("ws://192.168.16.42:9527/my_socket");
  // 監聽后端發來的消息,ws.onmessage起到監聽的作用,只要有消息過來函數會自動執行
  ws.onmessage = function (eventMessage) {
      console.log(eventMessage.data); // 獲取后端發來的消息
      var p = document.createElement("p");
      p.innerText = eventMessage.data;
      document.getElementById("chat_list").appendChild(p); // 將消息內容添加到div內
  };
  // 將我們輸入的內容發送給后端
  function send_msg() {
      var content = document.getElementById("content").value;
      ws.send(content);
  };

</script>
</html>

后端邏輯代碼

# -*- coding: utf-8 -*-
# @Time    : 2019/7/15 16:42

from flask import render_template,request,Flask
from geventwebsocket.handler import WebSocketHandler  # 提供WS協議處理
from geventwebsocket.server import WSGIServer # 承載服務
from geventwebsocket.websocket import WebSocket  # 語法提示

app = Flask(__name__)

user_socket_list = []
@app.route("/my_socket")
def my_socket():
    # 獲取當前客戶端與服務器的Socket連接
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    if user_socket:
            user_socket_list.append(user_socket)
            print(len(user_socket_list),user_socket_list)
        # 1 [<geventwebsocket.websocket.WebSocket object at 0x000001D0D70E1458>]
        # print(user_socket,"OK 連接已經建立好了,接下來發消息吧")
    while 1:
        # 等待前端將消息發送過來
        msg = user_socket.receive()
        print(msg)

        for usocket in user_socket_list:
            try:
                usocket.send(msg)
            except:
                continue

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

if __name__ == '__main__':
    http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler) # 這種啟動方式和app.run()不沖突,該啟動方式發什么請求都可以接受到
    http_serv.serve_forever()

流程

1、用戶在網頁請求http://192.168.16.42:9527/qunliao
2、請求/qunliao這個路由走后端對應的視圖函數gc返回qunliao.html這個頁面,
3、頁面在加載的過程中走到script代碼時建立WebSocket連接請求ws://192.168.16.42:9527/my_socket,
4、ws://192.168.16.42:9527/my_socket請求走后端對應的視圖函數,獲取當前客戶端與服務器的socket連接對象,調用該對象的receive方法,等待前端發來消息,
5、前端我們通過給input框綁定點擊事件,獲取用戶輸入的內容發送給服務器;
6、后端將前端發來的消息在發送給前端;
7、前端通過ws.onmessage這個事件監聽着后端過來的消息,只要有消息就會自動觸發函數執行並獲取數據;

第一步是瀏覽器向/quliao這個路徑發起請求:

jQuery

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>群聊</title>
</head>
<body>
<p>
    <input type="text" id="content">
    <button id="send_msg" >發送</button> <!--給按鈕綁定點擊事件-->
</p>

<div id="chat_list">

</div>
</body>
<script src="/static/jquery-3.4.1.js"></script>
<script type="application/javascript">
    var ws = new WebSocket("ws://192.168.16.42:9527/my_socket");
    // 監聽后端發來的消息,ws.onmessage起到監聽的作用,只要有消息過來函數會自動執行
    ws.onmessage = function (eventMessage) {
      console.log(eventMessage.data);       // 獲取后端發來的消息
      var p = document.createElement("p"); // 創建一個p標簽
      p.innerText = eventMessage.data;     // 將后端發來的數據添加到p標簽內
      $("#chat_list").append(p)            // 將p標簽添加到div內
    };
  // 將我們輸入的內容發送給后端
    $("#send_msg").click(function () {
        var content = $("#content").val();
        ws.send(content);
    })
</script>
</html>
前端代碼
from flask import render_template,request,Flask
from geventwebsocket.handler import WebSocketHandler  # 提供WS協議處理
from geventwebsocket.server import WSGIServer # 承載服務
from geventwebsocket.websocket import WebSocket  # 語法提示
app = Flask(__name__,static_folder="statics",static_url_path="/static")  # 獲取靜態文件
user_socket_list = []
@app.route("/my_socket")
def my_socket():
    # 獲取當前客戶端與服務器的Socket連接
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    if user_socket:
            user_socket_list.append(user_socket)
            print(len(user_socket_list),user_socket_list)
        # 1 [<geventwebsocket.websocket.WebSocket object at 0x000001D0D70E1458>]
        # print(user_socket,"OK 連接已經建立好了,接下來發消息吧")
    while 1:
        # 等待前端將消息發送過來
        msg = user_socket.receive()
        print(msg)
        for usocket in user_socket_list:
            try:
                usocket.send(msg)
            except:
                continue

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

if __name__ == '__main__':
    http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
    http_serv.serve_forever()
后端代碼

帶群昵稱的群聊

通過動態路由參數獲取前端傳過來的用戶名

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>群聊</title>
</head>
<body>
<input type="text" id="username">
<button id="login">登錄</button>
<p>
    <input type="text" id="content">
    <button id="send_msg" >發送</button> <!--給按鈕綁定點擊事件-->
</p>

<div id="chat_list">

</div>
</body>
<script src="/static/jquery-3.4.1.js"></script>
<script type="application/javascript">
    var ws = null; // 創建全局變量,ws多處使用

    $("#login").click(function () {
         var username = $("#username").val();
         console.log(username);
         // 創建一個websocket對象,建立websocket連接,更改了全局的ws,將用戶名拼接上
         ws = new WebSocket("ws://192.168.16.42:9527/my_socket/" + username);

        // 監聽后端發來的消息,ws.onmessage起到監聽的作用,只要有消息過來函數會自動執行
        ws.onmessage = function (eventMessage) {
            console.log(eventMessage.data);       // 獲取后端發來的消息
            var str_obj = JSON.parse(eventMessage.data);  // 反序列化,因為我們在發送給后端的時候是json
            var p = document.createElement("p"); // 創建一個p標簽
            $(p).text(str_obj.from_user +":"+str_obj.chat);     // 將dom對象轉換成jQuery對象,將后端發來的數據添加到p標簽內
            $("#chat_list").append(p)            // 將p標簽添加到div內
        };
    });

    // 將我們輸入的內容發送給后端
    $("#send_msg").click(function () {
        var content = $("#content").val();
        var username = $("#username").val();
        // 將要發送的內容封裝成自定義對象
        var sendStr = {
            from_user:username,
            chat:content
        };
        console.log(sendStr);
        // 序列化后發送給后端
        ws.send(JSON.stringify(sendStr));
    });
</script>
</html>
前端代碼
from flask import render_template,request,Flask
from geventwebsocket.handler import WebSocketHandler  # 提供WS協議處理
from geventwebsocket.server import WSGIServer # 承載服務
from geventwebsocket.websocket import WebSocket  # 語法提示
app = Flask(__name__,static_folder="statics",static_url_path="/static")
user_socket_dict = {}

# 建立websocket連接時,前端將名字發送過來了
@app.route("/my_socket/<username>")
def my_socket(username):
    # 獲取當前客戶端與服務器的Socket連接
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket

    if user_socket:
        # 以名字為key,連接對象為value添加到字典中
        user_socket_dict[username] = user_socket
    while 1:
        # 等待前端將消息發送過來,此時是json數據
        msg = user_socket.receive()
        for usocket in user_socket_dict.values():
            try:
                # 將收到的信息在發送給所有與服務器建立連接的前端
                usocket.send(msg)
            except:
                continue

@app.route("/qunliao")
def gc():
    return render_template("qunliaonicheng.html")

if __name__ == '__main__':
    http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
    http_serv.serve_forever()
后端代碼

效果:

websocket實現私聊

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>群聊</title>
</head>
<body>
我的昵稱:<input type="text" id="username">
<button id="login">登錄</button>
<p><input type="text" id="to_user">發送
    <input type="text" id="content">
    <button id="send_msg" >發送</button> <!--給按鈕綁定點擊事件-->
</p>

<div id="chat_list">

</div>
</body>
<script src="/static/jquery-3.4.1.js"></script>
<script type="application/javascript">
    var ws = null; // 創建全局變量,ws多處使用

    $("#login").click(function () {
         var username = $("#username").val();
         console.log(username);
         // 創建一個websocket對象,建立websocket連接,更改了全局的ws,將用戶名拼接上
         ws = new WebSocket("ws://192.168.16.42:9527/my_socket/" + username);

        // 監聽后端發來的消息,ws.onmessage起到監聽的作用,只要有消息過來函數會自動執行
        ws.onmessage = function (eventMessage) {
            console.log(eventMessage.data);       // 獲取后端發來的消息
            var str_obj = JSON.parse(eventMessage.data);  // 反序列化,因為我們在發送給后端的時候是json
            var p = document.createElement("p"); // 創建一個p標簽
            $(p).text(str_obj.from_user +":"+str_obj.chat);     // 將dom對象轉換成jQuery對象,將后端發來的數據添加到p標簽內
            $("#chat_list").append(p)            // 將p標簽添加到div內
        };
    });

    // 將我們輸入的內容發送給后端
    $("#send_msg").click(function () {
        var content = $("#content").val();
        var username = $("#username").val();
        var to_user = $("#to_user").val();
        // 將要發送的內容封裝成自定義對象
        var sendStr = {
            from_user:username,
            chat:content,
            to_user:to_user,
        };
        console.log(sendStr);
        // 序列化后發送給后端
        ws.send(JSON.stringify(sendStr));
    });
</script>
</html>
前端頁面
import json
from flask import render_template,request,Flask
from geventwebsocket.handler import WebSocketHandler  # 提供WS協議處理
from geventwebsocket.server import WSGIServer # 承載服務
from geventwebsocket.websocket import WebSocket  # 語法提示
app = Flask(__name__,static_folder="statics",static_url_path="/static")
user_socket_dict = {}

# 建立websocket連接時,前端將名字發送過來了
@app.route("/my_socket/<username>")
def my_socket(username):
    # 獲取當前客戶端與服務器的Socket連接
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket

    if user_socket:
        # 以名字為key,連接對象為value添加到字典中
        user_socket_dict[username] = user_socket
    while 1:
        # 等待前端將消息發送過來,此時是json數據
        msg = user_socket.receive()
        print(msg)    # {"from_user":"wuchao","chat":"123","to_user":"xiaohei"}
        # 反序列化
        msg_dict = json.loads(msg)
        # 查找字典中前端要發送信息給那個人的名字
        to_username = msg_dict.get("to_user")
        # 獲取目標人物的連接地址
        to_user_socket = user_socket_dict.get(to_username)
        # 將信息發送給目標人物
        to_user_socket.send(msg)

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

if __name__ == '__main__':
    http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
    http_serv.serve_forever()
后端代碼

效果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM