ナニー レベルには、ソース コード Django 統合チャネル (1) が付属しており、簡単なチャット機能を実現します。

目次

序文

私のブラインドBBを見たくない場合は、ここに直接ジャンプできます

1.Webソケット

1.1 ajax ポーリング

1.2 ロング ポール

1.3 ウェブソケット

2.チャンネル

2.1 WSGI

2.2 アスギ

3. Django 環境を準備する

3.1 インストール チャネル

3.2 Django プロジェクトを作成する

 3.3 チャット アプリケーションを作成する

3.4 インデックス ビューを追加する

3.5 chat/views.py でビュー関数を作成します。

3.6 ルートを保存するために、チャットで urls.py というファイルを作成します。

3.7 mysite/urls.py でルート全体を構成する

3.8 起動して確認する

4. Django でのチャネルの統合

4.1 構成環境

4.3 chat/views.py にビュー関数を作成する

4.4 chat/urls.py でルートを作成する

4.5 WebSocket 接続構成

4.6 ソケット ルーティングの構成

4.7 チャネル層の有効化

4.7.1 channels_redis のインストール

4.7.2 チャネル層の環境設定

4.7.3 環境が正常に構成されているかどうかのテスト

4.8 古いコードの置き換え

4.9 テスト

5. ソースコード参照


序文

インターネット上のブログの圧倒的多数は、送信側または受信側を同時にサーバーとして使用しています. それはばかげているのではないでしょうか...または、厄介なものはまったく実行できず、我慢できません. . しばらく勉強した後、乳母レベルのブログを書くことにしました 記事を統合し、記事の最後にソース コードを添付してください。

私のブラインドBBを見たくない場合は、ここに直接ジャンプできます

双方向通信を実現するために、websocket を選択しますが、Django 3.0 では Websocket が立ち上がるとサポートされないため、言葉が出ないので、ここではチャネル経由で Websocket を実装します。

1.Webソケット

        の話をする前にWebsocketlong pollと のajax轮询

1.1 ajax ポーリング

        ajaxポーリングの原理は非常に単純です。ブラウザが数秒ごとにリクエストを送信して、新しい情報があるかどうかをサーバーに問い合わせます。これはサーバー リソースの無駄です。プロジェクトが小さい場合は問題ありません。プロジェクトが大きい場合は、上司が直接行かせてくれます。

1.2 ロング ポール

  long poll実際、原理はajaxpolling。どちらもポーリングを使用しますが、ブロッキング モデル (電話をかけ続け、受信しなければ電話を切らない) を採用しています。つまり、クライアントが開始した後です。メッセージがない場合は、常にクライアントに応答を返しません。メッセージがあるまで戻りません. 戻った後、クライアントは再び接続を確立し、サイクルが繰り返されます.

  ajaxポーリングには、サーバーからの非常に高速な処理とリソース (速度) が必要です。long poll高い並行性、つまり同時に顧客を受け入れる能力 (サイトのサイズ) が必要です。

1.3 ウェブソケット

  WebSocketTCP1 つの接続で全二重通信を行うためのプロトコルです。WebSocketサーバーがデータをクライアントにアクティブにプッシュできるようにします。このプロトコルではWebSocket、クライアント ブラウザとサーバーはハンドシェイクを完了するだけで持続的な接続を確立し、ブラウザとサーバーの間で双方向のデータ転送を実行できます。

2.チャンネル

  Djangoネイティブにはサポートされていませんが、統合フレームワークを通じて実装WebSocketできますChannelsWebSocket

  ChannelsこれはDjangoプロジェクトの拡張フレームワークであり、プロトコルをDjangoサポートするだけでなく、複数のプロトコルHTTPもサポートしシステム統合してユーザー管理と認証を容易にします。WebSocketMQTTChannelsDjangoauthsession

2.1 WSGI

WSGI(Python Web Server Gateway Interface): Web サーバーと、 Python 言語用に定義されたWebアプリケーションまたはフレームワークとの間のシンプルで一般的なインターフェイス。

2.2 アスギ

ASGI(Asynchronous Web Server Gateway Interface): 非同期ゲートウェイ プロトコル インターフェイス。ネットワーク プロトコル サービスとアプリケーション間の標準インターフェイスであり、 、 などPython、さまざまな一般的なプロトコル タイプを処理できますHTTPHTTP2WebSocket

WSGIプロトコルモードに基づいておりHTTP、サポートしていませんがWebSocket現在開発中のいくつかの新しいプロトコル標準をサポートしていない一般的に使用されているものをASGI解決するために生まれました。同時に、元のモデルのサポートと拡張は、最高の拡張です。PythonWSGIWebASGIWSGIWebSocketASGIWSGI

3. Django 環境を準備する

この記事は、 Python 3.6+およびDjango 2.2+をサポートするChannels 3.0向けに書かれています。

python3 -m django --version

3.1 インストールchannels

pip install channels

3.2 Django プロジェクトを作成する

 3.3チャット アプリケーションを作成する

python manage.py startapp chat

chatアプリケーション がインストールされていることをプロジェクトに伝える必要があります。mysite/settings.pyファイルを編集し 、 INSTALLED_APPS'chat'設定に追加します次のようになります。

3.4 インデックス ビューを追加する

ここで、参加したいチャット ルームの名前を入力できるインデックス ビューである最初のビューを作成します。

templatesディレクトリにchatという名前のフォルダーを作成します。HTMLページを保存するために使用されます

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Chat Rooms</title>
</head>
<body>
    What chat room would you like to enter?<br>
    <input id="room-name-input" type="text" size="100"><br>
    <input id="room-name-submit" type="button" value="Enter">

    <script>
        document.querySelector('#room-name-input').focus();
        document.querySelector('#room-name-input').onkeyup = function(e) {
            if (e.keyCode === 13) {  // enter, return
                document.querySelector('#room-name-submit').click();
            }
        };

        document.querySelector('#room-name-submit').onclick = function(e) {
            var roomName = document.querySelector('#room-name-input').value;
            window.location.pathname = '/chat/' + roomName + '/';
        };
    </script>
</body>
</html>

3.5chat/views.py中ビュー関数を作成する場合:

# chat/views.py
from django.shortcuts import render

def index(request):
    return render(request, 'chat/index.html')

3.6chat中というファイルを作成した後urls.py用来存放路由:

# chat/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

 

3.7 mysite/urls.py でルート全体を構成する

# mysite/urls.py
from django.conf.urls import include
from django.urls import path
from django.contrib import admin

urlpatterns = [
    path('chat/', include('chat.urls')),
    path('admin/', admin.site.urls),
]

3.8 起動して確認する

 

Django は成功する準備ができています!

4. Django でのチャネルの統合

ここまでは、通常の Django アプリケーションを作成しただけで、Channels ライブラリはまったく使用していません。今こそ統合の時です。

まず、チャネルのルート ルーティング構成を作成します。Channels ルーティング構成は、Channels サーバーが HTTP リクエストを受信したときに実行するコードを Channels に伝えるという点で、Django の URLconf に似た ASGI アプリケーションです。

4.1 構成環境

mysite/asgi.pyファイルの下

この python ファイルがなくても、自分で手動で作成できます

# mysite/asgi.py
import os

from channels.routing import ProtocolTypeRouter
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    # Just HTTP for now. (We can add other protocols later.)
})

 知らせ:

     Django 2.2 には ASGI サポートが組み込まれていないため、Channel に代わる代替手段を使用する必要があります。mysite/asgi.py次のように作成します。

# mysite/asgi.py
import os

import django
from channels.http import AsgiHandler
from channels.routing import ProtocolTypeRouter

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
django.setup()

application = ProtocolTypeRouter({
  "http": AsgiHandler(),
  # Just HTTP for now. (We can add other protocols later.)
})

ここで、Channel Library をインストール済みアプリケーションのリストに追加します。mysite/settings.pyファイルを編集して設定'channels'に 追加します。チャネルをルート ルーティング構成にポイントする必要もあります。INSTALLED_APPS

 新しいものを開始すると、次の構成が成功します。

4.2ビューの追加

templates/ chatに新しい html ページ room.html を追加します

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Chat Room</title>
</head>
<body>
    <textarea id="chat-log" cols="100" rows="20"></textarea><br>
    <input id="chat-message-input" type="text" size="100"><br>
    <input id="chat-message-submit" type="button" value="Send">
    {
   
   { room_name|json_script:"room-name" }}
    <script>
        const roomName = JSON.parse(document.getElementById('room-name').textContent);

        const chatSocket = new WebSocket(
            'ws://'
            + window.location.host
            + '/ws/chat/'
            + roomName
            + '/'
        );

        chatSocket.onmessage = function(e) {
            const data = JSON.parse(e.data);
            document.querySelector('#chat-log').value += (data.message + '\n');
        };

        chatSocket.onclose = function(e) {
            console.error('Chat socket closed unexpectedly');
        };

        document.querySelector('#chat-message-input').focus();
        document.querySelector('#chat-message-input').onkeyup = function(e) {
            if (e.keyCode === 13) {  // enter, return
                document.querySelector('#chat-message-submit').click();
            }
        };

        document.querySelector('#chat-message-submit').onclick = function(e) {
            const messageInputDom = document.querySelector('#chat-message-input');
            const message = messageInputDom.value;
            chatSocket.send(JSON.stringify({
                'message': message
            }));
            messageInputDom.value = '';
        };
    </script>
</body>
</html>

4.3chat/views.pyビュー関数を作成する場合

# chat/views.py
from django.shortcuts import render

def index(request):
    return render(request, 'chat/index.html', {})

def room(request, room_name):
    return render(request, 'chat/room.html', {
        'room_name': room_name
    })

4.4chat/urls.pyルート作成にあたって

# chat/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('<str:room_name>/', views.room, name='room'),
]

4.5 WebSocket 接続構成

知らせ:

/ws/共通のパス プレフィックスを使用することをお勧めします   (たとえば、 WebSocket 接続を通常の HTTP 接続と区別するため)。これにより、特定の構成でチャネルを運用環境に簡単にデプロイできるようになります。

   新しいファイルを作成するchat/consumers.py

 次のコードを入れますchat/consumers.py

# chat/consumers.py
import json
from channels.generic.websocket import WebsocketConsumer

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.accept()

    def disconnect(self, close_code):
        pass

    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        self.send(text_data=json.dumps({
            'message': message
        }))

4.6 ソケット ルーティングの構成

chatコンシューマーへのルーティングを使用してアプリケーションのルーティング構成を作成する必要もあります

     新しいファイルを作成するchat/routing.py

 次のコードを入れますchat/routing.py

# chat/routing.py
from django.urls import re_path

from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
]

as_asgi()ユーザー接続ごとにコンシューマー インスタンスをインスタンス化する ASGI アプリケーションを取得するために、クラス メソッドが   呼び出されます。as_view()これは、要求された各 Django ビュー インスタンスに対して同じことを行うDjango の に似ています。

次のステップは、ルート ルーティング構成を chat.routingモジュールに向けることです。

# mysite/asgi.py
import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

application = ProtocolTypeRouter({
  "http": get_asgi_application(),
  "websocket": AuthMiddlewareStack(
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})

現時点では、設定して実行した後、チャットがまったくできないことがわかりました。!

これで終わりじゃない?. . . . . .

解決:

4.7チャネル層の有効化

バッキング ストアとして Redis を使用するチャネル レイヤーを使用します。Redis サーバーを起動するには

redis の起動時にエラーが発生した場合は、私の別の記事を参照してください:フラッシュで Windows の下で Redis サーバーを起動するためのソリューション

4.7.1 channels_redis のインストール

チャネルが Redis と対話する方法を知るようにする

pip install channels_redis

4.7.2 チャネル層の環境設定

mysite/settings.pyファイル内で、CHANNEL_LAYERS下部に設定を追加します

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

4.7.3 環境が正常に構成されているかどうかのテスト

import channels.layers
channel_layer = channels.layers.get_channel_layer()
from asgiref.sync import async_to_sync
async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})
async_to_sync(channel_layer.receive)('test_channel')

#结果:
{'type': 'hello'}

4.8 古いコードの置き換え

 チャネル レイヤーができたので、/chat/consumer. に次のコードを記述して、chat/consumers.py古いコードを置き換えます。

# chat/consumers.py
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name

        # Join room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )

        self.accept()

    def disconnect(self, close_code):
        # Leave room group
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # Send message to room group
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # Receive message from room group
    def chat_message(self, event):
        message = event['message']

        # Send message to WebSocket
        self.send(text_data=json.dumps({
            'message': message
        }))

    ユーザーがメッセージを投稿すると、JavaScript 関数が WebSocket 経由でメッセージを ChatConsumer に送信します。ChatConsumer はメッセージを受信し、ルーム名に対応するグループに転送します。同じグループ内 (つまり、同じルーム内) の各 ChatConsumer は、グループからメッセージを受信し、WebSocket を介してそれらを JavaScript に転送し、チャット ログに追加して、チャット機能を有効にします。

ChatConsumerコードのいくつかの部分の詳細な説明:

  • self.scope['url_route']['kwargs']['room_name']

    • 'room_name'chat/routing.py コンシューマーへの WebSocket 接続を開く URL ルートからパラメーターを取得します。
    • 各コンシューマーには、その接続に関する情報を含むスコープがあります。これには、特に、URL ルートからの位置引数またはキーワード引数と、現在認証されているユーザー (存在する場合) が含まれます。
  • self.room_group_name = 'chat_%s' % self.room_name

    • 引用符やエスケープなしで、ユーザーが指定したルーム名から直接 Channels グループ名を作成します。
    • グループ名には、文字、数字、ハイフン、およびピリオドのみを含めることができます。したがって、このコード例は、他の文字を含む部屋名では失敗します。
  • async_to_sync(self.channel_layer.group_add)(...)

    • グループに参加します。
    • ChatConsumer は同期 WebsocketConsumer ですが、非同期チャネル レイヤー メソッドを呼び出しているため、async_to_sync(...) ラッパーが必要です。(すべてのチャネル層メソッドは非同期です。)
    • グループ名は、ASCII 英数字、ハイフン、およびピリオドに制限されています。このコードはルーム名から直接グループ名を作成するため、グループ名として無効な文字がルーム名に含まれていると失敗します。
  • self.accept()

    • WebSocket 接続を受け入れます。
    • connect() メソッドで accept() を呼び出さない場合、接続は拒否されて閉じられます。たとえば、要求しているユーザーが要求された操作を実行する権限がないため、接続を拒否したい場合があります。
    • 接続を受け入れることを選択した場合は、 connect() の最後の操作として accept() を呼び出すことをお勧めします。
  • async_to_sync(self.channel_layer.group_discard)(...)

    • グループを離れます。
  • async_to_sync(self.channel_layer.group_send)

    • グループにイベントを送信します。
    • イベントには、'type'イベントを受け取ったコンシューマーで呼び出されるメソッドの名前に対応する特別なキーがあります。

4.9 テスト

 これまでのところ、Django での単純なチャネルの統合は完了しています。 

次の記事では、ソケット カメラのリアルタイム ビデオ伝送を実現する Django 統合チャネルについて説明します。

5. ソースコード参照

コード クラウド: Django 統合チャネル: Django 統合チャネル シリーズ

おすすめ

転載: blog.csdn.net/weixin_46504244/article/details/121327673