目次
私のブラインドBBを見たくない場合は、ここに直接ジャンプできます
3.5 chat/views.py でビュー関数を作成します。
3.6 ルートを保存するために、チャットで urls.py というファイルを作成します。
3.7 mysite/urls.py でルート全体を構成する
序文
インターネット上のブログの圧倒的多数は、送信側または受信側を同時にサーバーとして使用しています. それはばかげているのではないでしょうか...または、厄介なものはまったく実行できず、我慢できません. . しばらく勉強した後、乳母レベルのブログを書くことにしました 記事を統合し、記事の最後にソース コードを添付してください。
私のブラインドBBを見たくない場合は、ここに直接ジャンプできます
双方向通信を実現するために、websocket を選択しますが、Django 3.0 では Websocket が立ち上がるとサポートされないため、言葉が出ないので、ここではチャネル経由で Websocket を実装します。
1.Webソケット
の話をする前にWebsocket
、long poll
と のajax轮询
。
1.1 ajax ポーリング
ajaxポーリングの原理は非常に単純です。ブラウザが数秒ごとにリクエストを送信して、新しい情報があるかどうかをサーバーに問い合わせます。これはサーバー リソースの無駄です。プロジェクトが小さい場合は問題ありません。プロジェクトが大きい場合は、上司が直接行かせてくれます。
1.2 ロング ポール
long poll
実際、原理はajax
polling。どちらもポーリングを使用しますが、ブロッキング モデル (電話をかけ続け、受信しなければ電話を切らない) を採用しています。つまり、クライアントが開始した後です。メッセージがない場合は、常にクライアントに応答を返しません。メッセージがあるまで戻りません. 戻った後、クライアントは再び接続を確立し、サイクルが繰り返されます.
ajax
ポーリングには、サーバーからの非常に高速な処理とリソース (速度) が必要です。long poll
高い並行性、つまり同時に顧客を受け入れる能力 (サイトのサイズ) が必要です。
1.3 ウェブソケット
WebSocket
TCP
1 つの接続で全二重通信を行うためのプロトコルです。WebSocket
サーバーがデータをクライアントにアクティブにプッシュできるようにします。このプロトコルではWebSocket
、クライアント ブラウザとサーバーはハンドシェイクを完了するだけで持続的な接続を確立し、ブラウザとサーバーの間で双方向のデータ転送を実行できます。
2.チャンネル
Django
ネイティブにはサポートされていませんが、統合フレームワークを通じて実装WebSocket
できますChannels
WebSocket
Channels
これはDjangoプロジェクトの拡張フレームワークであり、プロトコルをDjango
サポートするだけでなく、複数のプロトコルHTTP
もサポートし、システムを統合してユーザー管理と認証を容易にします。WebSocket
MQTT
Channels
Django
auth
session
2.1 WSGI
WSGI(Python Web Server Gateway Interface)
: Web サーバーと、 Python 言語用に定義されたWeb
アプリケーションまたはフレームワークとの間のシンプルで一般的なインターフェイス。
2.2 アスギ
ASGI(Asynchronous Web Server Gateway Interface)
: 非同期ゲートウェイ プロトコル インターフェイス。ネットワーク プロトコル サービスとアプリケーション間の標準インターフェイスであり、 、、 などPython
、さまざまな一般的なプロトコル タイプを処理できます。HTTP
HTTP2
WebSocket
WSGI
プロトコルモードに基づいておりHTTP
、サポートしていませんがWebSocket
、現在開発中のいくつかの新しいプロトコル標準をサポートしていない一般的に使用されているものをASGI
解決するために生まれました。同時に、元のモデルのサポートと拡張は、最高の拡張です。Python
WSGI
Web
ASGI
WSGI
WebSocket
ASGI
WSGI
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 統合チャネル シリーズ