使用django+websocket+redis+channels實現簡易聊天室

来源:https://www.cnblogs.com/minqiliang/archive/2022/08/03/16548465.html
-Advertisement-
Play Games

使用django+websocket+redis+channels實現簡易聊天室 1.創建一個django項目 從存儲項目的文件夾進入cmd命令行終端,輸入以下命令創建chatroom項目 django-admin startproject chatroom 然後再進入項目文件夾,打開cmd命令行終 ...


使用django+websocket+redis+channels實現簡易聊天室

1.創建一個django項目

從存儲項目的文件夾進入cmd命令行終端,輸入以下命令創建chatroom項目

django-admin startproject chatroom

然後再進入項目文件夾,打開cmd命令行終端,輸入以下命令創建chat應用

python manage.py startapp chat

2.安裝所需模塊

channels的功能必須依賴於redis資料庫,除了安裝channels之外,還需安裝channels_redis模塊,我們使用pip指令分別安裝channels和channels_redis,指令如下:

pip install channels
pip install channels_redis
#channels的功能依賴模塊
pip install pypiwin32

3.在django中配置channels

(1)在項目應用chat里新建urls.py文件

(2)在chatroom文件夾里創建文件consumers.py和routing.py,文件名可以自行命名

(3)在項目應用chat里新建templates文件夾,在templates文件夾里創建模板文件chat.html和room.html,項目結構如下:

vZ0mUe.png

(4)執行整個項目的數據遷移,因為channels需要使用django內置的會話session機制,用於區分和識別每個用戶的身份信息

(5)在django的settings.py里將第三方功能應用channels和chat添加到chatroom,配置如下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'channels',
    'chat'
]

(6)由於channels的功能依賴與redis資料庫,因此還需在settings.py里設置channels的功能設置,配置信息如下:

ASGI_APPLICATION = 'chatroom.routing.application'
CHANNEL_LAYERS={
    'default':{
        'BACKEND':'channels_redis.core.RedisChannelLayer',
        'CONFIG':{
            "hosts":[('127.0.0.1',6379)],
        },
    },
}

(7)功能配置CHANNEL_LAYERS用於設置redis資料庫的連接方式,ASGI_APPLICATION指向chatroom的routing.py定義的application對象,該對象把django與channels建立連接,打開chatrooom的routing.py添加如下內容:

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter
from channels.routing import URLRouter
from .urls import websocket_urlpatterns
application = ProtocolTypeRouter({
    'websocket':AuthMiddlewareStack(
        URLRouter(
            websocket_urlpatterns
        )
    ),
})

(8)在chatroom的urls.py中定義路由對象urlpatterns和websocket_urlpatterns,代碼如下:

from django.urls import path,include
from .consumers import ChatConsumer

urlpatterns = [
    path("",include(("chat.urls","chat"),namespace="chat"))
]

websocket_urlpatterns=[
    #使用同步方式實現
    #path('ws/chat/<room_name>/',ChatConsumer),
    #如果使用非同步方式實現,路由的視圖必須調用as_asgi()
    path('ws/chat/<room_name>/',ChatConsumer.as_asgi()),
]

(9)在chatroom的consumers.py中定義視圖類ChatConsumer,代碼如下:

from channels.generic.websocket import AsyncWebsocketConsumer
import json

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        print("一個客戶端連接了伺服器")
        self.room_name=self.scope['url_route']['kwargs']['room_name']
        self.room_group_name='chat_%s' % self.room_name
        #join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await  self.accept()

    async def disconnect(self, code):
        # leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )
        print("一個客戶端斷開了連接")

    # receive message from websocket
    async def receive(self, text_data=None, bytes_data=None):
        text_data_json=json.loads(text_data)
        message=text_data_json["message"]
        # send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type':'chat_message',
                'message':message
            }
        )

    # receive message from room group
    async def chat_message(self,event):
        message=event['message']
        # send message to websocket
        await self.send(text_data=json.dumps({
            'message':message
        }))

4.web線上聊天功能

(1)在項目應用chat的urls.py中分別定義路由newChat和room,代碼如下:

from django.urls import path
from .views import *

urlpatterns = [
    #用於開啟新的聊天室
    path('',newChat,name="newChat"),
    #創建聊天室
    path('<room_name>/',room,name="room")
]

(2)在chat的views.py中定義視圖,代碼如下:

from django.shortcuts import render


#用於創建或進入聊天室
def newChat(request):
    return render(request,'chat.html',locals())

#創建聊天室
def room(request,room_name):
    return render(request,'room.html',locals())

(3)編寫chat.html模板文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>請輸入聊天室名稱</div>
<br/>
<input id="input" type="text" size="30" />
<br/>
<input id="submit" type="button" value="進入">

<script>
    document.querySelector('#input').focus();
    document.querySelector('#input').onkeyup=function (e){
        if (e.keyCode===13){
            document.querySelector('#submit').click();
        }
    };
    document.querySelector('#submit').onclick=function (e){
        var roomName=document.querySelector('#input').value;
        window.location.pathname='/'+roomName + '/';
    }
</script>
</body>
</html>

(4)編寫room.html模板文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>聊天室{{ room_name }}</title>
</head>
<body>
<textarea id="chat_log" cols="50" rows="6"></textarea>
<br/>
<input id="input" type="text" size="50"/><br/>
<input id="submit" type="button" value="發送"/>
<script>
    var roomName='{{ room_name }}';
    var chatSocket=new WebSocket(
        'ws://' + window.location.host+'/ws/chat/' + roomName +'/'
    );

    {#將chat發送的數據顯示在多行文本輸入框中#}
    chatSocket.onmessage=function (e){
        var data=JSON.parse(e.data);
        var message=data['message'];
        document.querySelector('#chat_log').value+=(message +'\n');
    };

    {#關閉網頁與chat的Channels連接#}
    chatSocket.onclose=function (e){
        console.error('Chat socket closed unexpectedly');
    };

    document.querySelector('#input').focus();
    document.querySelector('#input').onkeyup=function (e){
        if (e.keyCode===13){
            document.querySelector('#submit').click();
        }
    };

    {#網頁向chat的channels發送數據#}
    document.querySelector('#submit').onclick=function (e){
        var messageInputDom = document.querySelector('#input');
        var message=messageInputDom.value;
        chatSocket.send(JSON.stringify({
            'message':message
        }));
        messageInputDom.value='';
    }

</script>
</body>
</html>

5.測試聊天室功能

運行項目,打開谷歌瀏覽器並訪問127.0.0.1:8000,在文本輸入框輸入聊天室名稱,並單擊進入,如下圖所示:

vZ0VHO.png

當成功創建聊天室room0001後,打開另一個瀏覽器訪問127.0.0.1:8000/room0001,聊天室已有兩位用戶線上,然後使用谷歌瀏覽器發送消息,發現在另一瀏覽器可以實時看到消息內容,如下圖所示:

vZ0eED.png


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 表格標簽 1.1主要作用 顯示和展示數據美觀、良好。 1.2基本語法 <table> <tr> <td>單元格內的文字</td> ... </tr> ... </table> <table></table>用來定義表格的標簽 <tr></tr>標簽用於定義表格中的行,必須鑲嵌在<table>< ...
  • 在設計網頁的時候常常遇到這種情況:一個元素使用的樣式與另一個元素完全相同,但又添加了額外的樣式。 通常會在 HTML 中給元素定義兩個 class,一個通用樣式,一個特殊樣式。 普通CSS的實現 接下來以警告框為例進行講,解4種類型 | 類型 | 說明 | | | | | info | 信息!請註意 ...
  • 如果你有玩過 🎮 《王者榮耀》、《陰陽師》 等手游,一定註意到過它的啟動動畫、皮膚立繪卡片等場景,經常採用靜態底圖加局部液態流動效果的簡單動畫,本文使用前端開發技術,結合 SVG 和 CSS 來實現類似的液化流動效果。本文包含的知識點主要包括:mask-image 遮罩、feTurbulence ... ...
  • 一個工作薄中快速新建多個數據表 一、建立數據源數表 將所有數據統一錄入到本數據源表中,併進行統一排列數據。 註意:這裡的序號很重要,是對應後面工作表格獲取數據的來源,具體見公式設置。 二、建立一個表格模板 ① 將自己需要的表格進行製作及調整格式。 註意:做好表格列印格式調整。 ② 表格做好讀取表格名 ...
  • 1.用戶定義 在前面的案例中,我們的登錄用戶是基於配置文件來配置的(本質是基於記憶體),但是在實際開發中,這種方式肯定是不可取的,在實際項目中,用戶信息肯定要存入資料庫之中。 Spring Security支持多種用戶定義方式,接下來我們就逐個來看一下這些定義方式。通過前面的介紹(參見3小節),大家對 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 1.文件上傳 新建空項目 準備工作 在maven倉庫里下載commons io 和 commons fileupload兩個jar包 實用類介紹 文件上傳註意事項 為保證伺服器安全,上傳文件應該放在外界無法直接訪問的目錄下,比如放在WEB-INF目錄下 為防止文件覆蓋現象發生,要為上傳文件產生一個唯 ...
  • Java概述 什麼是Java? Java 是一種編程語言和計算平臺,由 Sun Microsystems 在 1995 年首次發佈。它從微末起步,逐漸發展為當今數字世界中很大一部分資產所依賴的基礎,是用於構建許多服務和應用程式的可靠平臺。面向未來的創新產品和數字服務也仍然依賴 Java。 儘管大多數 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...