我们知道python有socket包可以直接实现socket通信。

但在使用django时,不太适用于socket的方式与前端交互,对此django有channels来很好的支持socket通信。参考了网上很多资料之后发现写的不是很详细,最详细的是官方的资料。

项目地址:

GitHub - Wellbulizy/django-socket-channels: django-channels实现socket通信的简单例子

参考资料

Channels官方资料:

Introduction — Channels 3.0.4 documentation

Pypi-channels-redis:

channels-redis · PyPI

版本

Python:anaconda3/py3.7.2

Linux Centos8 localhost.localdomain 4.18.0-240.el8.x86_64 x86_64 x86_64 x86_64 GNU/Linux

Django: 2.2.16

项目结构

后续说明根据项目结构目录来讲解,请记住这个项目结构的文件。

页面代码编写

在传统的socket编写时,我们只需要一个端口,你发我接 + 我发你接,互相通信即完事了,然后突然转到django 的channels很难理解。其实原理是一样的,需要有路由中间件来区分web socket通信。

Ps:教程还是官网最详细,这里粗略带过,真的建议去看channels的官方

先不考虑socket通信,我们简单的把聊天室的界面做出来

dsocket/urls.py

from django.conf.urls import include
from django.contrib import admin
from django.urls import pathurlpatterns = [path('chat/', include('mysite.urls')),path('admin/', admin.site.urls),
]

#指向app的urls路径↓

mysite/urls.py

from django.urls import pathfrom . import viewsurlpatterns = [path('', views.index, name='index'),path('<str:room_name>/', views.room, name='room'),]

#因为模板这些设置是默认的,不需要更改settings可以直接创建目录并添加html文件

mysite/templates/index.html

<!-- chat/templates/chat/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, returndocument.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>

mysite/templates/room.html

#代码太长,稍微压缩了一些行,所以看上去可能不太美观…

<!-- chat/templates/chat/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, returndocument.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>

前置验证

启动项目:

Python manage.py runserver 192.168.70.132:8008

通过以上步骤,聊天室socket的界面暂时是OK了,访问如下

输入内容按回车,会跳转到聊天室:

当然这里只是聊天室,核心的通信功能都没有,F12大概能看到通信报错

socket代码编写

现在到了核心代码编写部分,我们需要加入channels的中间件,拦截请求识别请求类型,需要更改settings.py,由于官方和网上教程都是免密的redis配置,所以我到另一个channels-redis的官网找到了带密码的配置内容。

vim /dsocket/settings.py

#INSTALLED_APPS添加channels插件,如果已经有自定义的中间件,自己看情况添加

INSTALLED_APPS = ['mysite',   #app的名字'channels','django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',
]
#添加下面的内容,单会话通信不需要
ASGI_APPLICATION = 'dsocket.asgi.application'
CHANNEL_LAYERS = {'default': {'BACKEND': 'channels_redis.core.RedisChannelLayer','CONFIG': {"hosts": ["redis://:123456@127.0.0.1:6379/6"],#免密:"hosts": [('127.0.0.1', 6379)],},},
}

vim /dsocket/asgi.py
        该文件的作用是请求拦截中间件,如下有识别http与websocket请求(前缀ws://或wss://),根据不同的请求做不同的处理。

import os
import django
from channels.auth import AuthMiddlewareStack
from channels.http import AsgiHandler
from channels.routing import ProtocolTypeRouter,URLRouteros.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dsocket.settings')
django.setup()
from django.urls import re_path
from mysite import consumers
websocket_urlpatterns = [re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),]application = ProtocolTypeRouter({"http": AsgiHandler(),  #django3这里有区别,这里只是django2的写法"websocket": AuthMiddlewareStack(URLRouter(websocket_urlpatterns)),
})

单会话vim /mysite/consumers.py

#这是一个单会话通信的处理代码

class ChatConsumer(WebsocketConsumer):def connect(self):self.accept()def disconnect(self, close_code):passdef receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json['message']self.send(text_data=json.dumps({'message': message}))

什么是单会话通信?如果你同时打开多个聊天室,比如http://192.168.70.132:8008/chat/rowb/开两个界面,两个界面互相输入的信息都只有自己能看到。如果需要在同一个聊天室的都能看到,那需要启动通道层。这就是上面settings.py里配置redis的作用。下面即启用通道层后的consumers.py代码。

多会话 /mysite/consumers.py

对比上面的单会话模式,逻辑上加入了同一个room的对象会加入到组中,即变成多对一的模式,在处理回信时发送给一个组。而不是单独回信与发起者。

import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumerclass ChatConsumer(WebsocketConsumer):#新的socket函数,支持广播def connect(self):self.room_name = self.scope['url_route']['kwargs']['room_name']self.room_group_name = 'chat_%s' % self.room_name# Join room groupasync_to_sync(self.channel_layer.group_add)(self.room_group_name,self.channel_name)self.accept()def disconnect(self, close_code):# Leave room groupasync_to_sync(self.channel_layer.group_discard)(self.room_group_name,self.channel_name)# Receive message from WebSocketdef receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json['message']# Send message to room groupasync_to_sync(self.channel_layer.group_send)(self.room_group_name,{'type': 'chat_message','message': message})# Receive message from room groupdef chat_message(self, event):message = event['message']# Send message to WebSocketself.send(text_data=json.dumps({'message': message}))

常见错误

ModuleNotFoundError: No module named 'django.core.asgi'
官方asgi.py的坑,其实这个导入没有必要,删掉不影响
aioredis.errors.AuthError: NOAUTH Authentication required.
Redis密码错误,或者redis需要密码,但是你没有配置

初始化运行

因为启用了redis的会话认证,django的会话框架需要数据库,所以要migrate初始化迁移应用数据库更改

python manage.py migrate

Operations to perform:

Apply all migrations: admin, auth, contenttypes, sessions

Running migrations:

Applying contenttypes.0001_initial... OK

Applying auth.0001_initial... OK

Applying admin.0001_initial... OK

Applying admin.0002_logentry_remove_auto_add... OK

Applying admin.0003_logentry_add_action_flag_choices... OK

Applying contenttypes.0002_remove_content_type_name... OK

Applying auth.0002_alter_permission_name_max_length... OK

Applying auth.0003_alter_user_email_max_length... OK

Applying auth.0004_alter_user_username_opts... OK

Applying auth.0005_alter_user_last_login_null... OK

Applying auth.0006_require_contenttypes_0002... OK

Applying auth.0007_alter_validators_add_error_messages... OK

Applying auth.0008_alter_user_username_max_length... OK

Applying auth.0009_alter_user_last_name_max_length... OK

Applying auth.0010_alter_group_name_max_length... OK

Applying auth.0011_update_proxy_permissions... OK

Applying sessions.0001_initial... OK

#启动django后台

python manage.py runserver 192.168.70.132:8008

socket监听验证

运行项目后,会发现启动的信息变了,比如下面有starting asgi/channels即表示监听了socket的请求。

Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
October 1, 2020 - 21:31:22
Django version 2.2.16, using settings dsocket.settings'
Starting ASGI/Channels version 3.0.0 development server at http://192.168.70.132:8008/
Quit the server with CONTROL-C.

django channels socket通信实现相关推荐

  1. Django Channels 入门指南

    http://www.oschina.NET/translate/in_deep_with_django_channels_the_future_of_real_time_apps_in_django ...

  2. 基于Java NIO的Socket通信

    基于Java NIO的Socket通信 Java NIO模式的Socket通信,是一种同步非阻塞IO设计模式,它为Reactor模式实现提供了基础. 下面看看,Java实现的一个服务端和客户端通信的例 ...

  3. java socket发送定长报文_一个基于TCP协议的Socket通信实例

    原标题:一个基于TCP协议的Socket通信实例 1. 前言 一般接口对接多以http/https或webservice的方式,socket方式的对接比较少并且会有一些难度.正好前段时间完成了一个so ...

  4. Java Socket实战之六 使用NIO包实现Socket通信

    2019独角兽企业重金招聘Python工程师标准>>> 本文地址:http://blog.csdn.net/kongxx/article/details/7288896 Java S ...

  5. Django channels摄像头实时视频传输

    Django channels摄像头实时视频传输(视屏能传别的当然也能传拉) 前言 不想看我瞎扯可以直接跳到这 服务端 步骤 解释 发送端 接收端 运行 前言 (网上绝大多数博客都是发送端或者接收端同 ...

  6. Python+Django+channels实现websocket

    Python+Django+channels实现websocket 前言 公司需要实现一个长连接,用的Python的Django框架.研究了很长时间,发现Django+channels可以实现webs ...

  7. Django Channels 原理

    Django Channels 是一个为 Django 提供异步扩展的库,通常主要用来提供 WebSocket 支持和后台任务. 原理 它的原理是将 Django 分为 2 种进程类型: 一个用于处理 ...

  8. python 网络编程之Socket通信案例消息发送与接收

    背景 网络编程是python编程中的一项基本技术.本文将实现一个简单的Socket通信案例消息发送与接收 正文 在python中的socket编程的大致流程图如上所示 我们来首先编写客户端的代码: # ...

  9. C# Socket系列三 socket通信的封包和拆包

    通过系列二 我们已经实现了socket的简单通信 接下来我们测试一下,在时间应用的场景下,我们会快速且大量的传输数据的情况! 1 class Program 2 { 3 static void Mai ...

最新文章

  1. Sharepoint 2010 网站无法检索到部分AD用户
  2. (5) DSP28335--SCI
  3. 计算(a+b)/c的值(信息学奥赛一本通-T1008)
  4. Kali Linux 从入门到精通(二)-安装
  5. python requests post请求_Python“requests”模块中的POST请求无法正常工作
  6. 【】oracle当前用户下有什么表?
  7. 饭卡可以用水冲洗吗_关于饭卡使用与管理的规定
  8. 火狐firebug和firepath插件安装方法(最新)
  9. java 闰年闰月_什么是闰年,闰年和闰月的区别
  10. 打开conda环境报错:UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0x9a in position 317: illegal multibyt
  11. win10如何重装系统(联想笔记本)
  12. 基于RT1052 Aworks 测试PXP图像混合功能(十三)
  13. Leaflet地图框架使用手册
  14. 深恶痛绝!关闭win10自动更新的办法
  15. 面向对象之多态以及进阶
  16. 交互设计基本功!5个值得学习的APP交互方式
  17. 企业如何做好员工关怀,减少人才流失
  18. 关于Python的一些要点
  19. jCO--http://www.cnblogs.com/zfswff/p/5671148.html
  20. 诚之和:SQL 左连接 - 示例连接语句语法

热门文章

  1. 言简意赅之二进制运算符口诀
  2. Redis主从复制哨兵模式自动切换
  3. 计算机网络 —— TCP的三次握手四次挥手
  4. 国际最顶尖的AI技术发展,愈像一场比拼资金与人才的竞赛
  5. 电脑软件:推荐七款实用的效率神器
  6. 简单修改nginx的配置,限制指定IP访问指定页面
  7. 运营商网络之163/169的概念
  8. 基于keras实现房价预测 (神经网络入门)
  9. 什么叫序数_什么是序数
  10. iframe 边框去除,使用大全