当前位置:   article > 正文

websocke在django中使用_websocket在django中使用教程

websocket在django中使用教程

0. websocket介绍:

channels 4.0之后默认不带Daphne服务器了。

解决方案可以有两种:
1.指定channels的版本为3.x;
2.安装时使用pip3 install -U channels[“daphne”]

一. 后端

1. 安装(基于django3.x)

 pip3 install channels==3.0.3  -i https://pypi.douban.com/simple

 2. settings配置

 a. app注册

  1. INSTALLED_APPS = [
  2. 'channels',
  3. ]

b. 配置变量

  1. ASGI_APPLICATION = "qq_chart.asgi.application"
  2. ASGI_APPLICATION = '当前项目名同名的文件名.asgi.application'

3. 修改asgi文件(默认不支持websocket,只支持http)

  1. import os
  2. from django.core.asgi import get_asgi_application
  3. from channels.routing import ProtocolTypeRouter, URLRouter
  4. from . import routings
  5. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'qq_chart.settings')
  6. # application = get_asgi_application()
  7. application = ProtocolTypeRouter({
  8. 'http':get_asgi_application(),
  9. 'websocket':URLRouter(routings.websocket_urlpatterns)
  10. })

4. 在settings.py同级目录下创建routings.py 路由

  1. from django.urls import re_path
  2. from app01 import consumers
  3. websocket_urlpatterns = [
  4. re_path(r'ws/(?P<group>\w+)/$', consumers.ChatConsumer.as_asgi())
  5. ]

5. 创建websocket视图 consumers.py

  1. from channels.exceptions import StopConsumer
  2. from channels.generic.websocket import WebsocketConsumer
  3. # 异步改成同步
  4. from asgiref.sync import async_to_sync
  5. class ChatConsumer(WebsocketConsumer):
  6. def websocket_connect(self, message):
  7. '''客户端请求建立链接时 自动触发'''
  8. self.accept() # 建立链接 并且自动帮你维护每一个客户端
  9. def websocket_receive(self, message):
  10. '''客户端发送数据过来 自动触发'''
  11. print(message)
  12. self.send('小心电信诈骗')
  13. def websocket_disconnect(self, message):
  14. '''客户端断开链接之后 自动触发'''
  15. print('断开链接')
  16. raise StopConsumer()

群聊

这里放入内存中,也可以选择放入redis中

pip3 install channels_redis

# settings.py
# 群聊配置

# 无密码1 
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [('IP', 6379)]
        },
    },
}

# 无密码2 选择使用的库
CHANNEL_LAYERS = {
    'default': {
    'BACKEND': 'channels_redis.core.RedisChannelLayer',
    'CONFIG': {"hosts": ["redis://IP:6379/1"],},
    },

# 有密码
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": ["redis://:password@IP:6379/0"],
            # SECRET_KEY settings内置的
            "symmetric_encryption_keys": [SECRET_KEY],
        },
    },
}

配置

  1. # 群聊配置
  2. CHANNEL_LAYERS = {
  3. "default": {
  4. "BACKEND": "channels.layers.InMemoryChannelLayer",
  5. }
  6. }

视图改写1

  1. """
  2. websocket逻辑
  3. """
  4. from channels.generic.websocket import WebsocketConsumer
  5. from channels.exceptions import StopConsumer
  6. from asgiref.sync import async_to_sync
  7. class ChatConsumer(WebsocketConsumer):
  8. # 有客户端来向后端发送websocket连接的请求,自动触发
  9. def websocket_connect(self, message):
  10. # 允许创建链接
  11. self.accept()
  12. print('有人来连接了')
  13. # 不允许连接
  14. # raise StopConsumer()
  15. # 服务端与客户端发送消息
  16. # self.send(text_data='你好')
  17. # 群聊的配置
  18. # 将客户端的连接对象加入内存/redis
  19. # 1999群号,这个过程是异步的,要修改成同步的
  20. # self.channel_name当前用户
  21. group = self.scope['url_route']['kwargs'].get('group')
  22. async_to_sync(self.channel_layer.group_add)(group, self.channel_name)
  23. # 浏览器基于websocket向后端发送数据,自动触发
  24. def websocket_receive(self, message):
  25. print('接收到消息----》', message)
  26. text = message.get('text')
  27. if text == 'close':
  28. # 服务端主动断开
  29. self.close()
  30. # 可以让websocket_disconnect函数不执行
  31. raise StopConsumer()
  32. # 给一个人回复
  33. # self.send(text_data='收到了')
  34. # 群聊
  35. # 通知组内的所有客户端,去执行xx_oo的方法,
  36. group = self.scope['url_route']['kwargs'].get('group')
  37. async_to_sync(self.channel_layer.group_send)(group, {'type': 'xx.oo', 'message': message})
  38. def xx_oo(self, event):
  39. """
  40. 群聊
  41. :return:
  42. """
  43. print('--------->', event['message'])
  44. text = event['message']['text']
  45. # 给所有人回复
  46. self.send(text)
  47. # 当客户端/服务端主动断开连接自动触发
  48. def websocket_disconnect(self, message):
  49. group = self.scope['url_route']['kwargs'].get('group')
  50. print('客户端主动断开连接了')
  51. # 可以让websocket_disconnect函数不执行
  52. # 群聊断开
  53. async_to_sync(self.channel_layer.group_discard)(group, self.channel_name) # self.channel_name当前名字
  54. raise StopConsumer()

视图改写2

  1. """
  2. websocket逻辑
  3. """
  4. import json
  5. from channels.generic.websocket import WebsocketConsumer
  6. from channels.exceptions import StopConsumer
  7. from asgiref.sync import async_to_sync
  8. from chart import models
  9. class ChatConsumer(WebsocketConsumer):
  10. # 有客户端来向后端发送websocket连接的请求,自动触发
  11. def websocket_connect(self, message):
  12. # 允许创建链接
  13. self.accept()
  14. print('有人来连接了-----群聊')
  15. # 不允许连接
  16. # raise StopConsumer()
  17. # 服务端与客户端发送消息
  18. # self.send(text_data='你好')
  19. # 群聊的配置
  20. # 将客户端的连接对象加入内存/redis
  21. # 1999群号,这个过程是异步的,要修改成同步的
  22. # self.channel_name当前用户
  23. group = self.scope['url_route']['kwargs'].get('group')
  24. username = self.scope['url_route']['kwargs'].get('username')
  25. query = models.Chart_Record_all.objects.filter(chart_num=group, is_delete=False, is_active=True)
  26. for item in query:
  27. if item.username:
  28. # print('发言人:', item.username)
  29. self.send(
  30. json.dumps(
  31. {'username': item.username.username, 'text': item.text, 'timer': str(item.create_time)[0:19]},
  32. ensure_ascii=False))
  33. async_to_sync(self.channel_layer.group_add)(group, self.channel_name)
  34. # 获取当前组的发言记录
  35. # 浏览器基于websocket向后端发送数据,自动触发
  36. def websocket_receive(self, message):
  37. print('接收到消息----》', message)
  38. text = message.get('text')
  39. print(text)
  40. # 给一个人回复
  41. # self.send(text_data='收到了')
  42. # 群聊
  43. # 通知组内的所有客户端,去执行xx_oo的方法,
  44. # group = self.scope['url_route']['kwargs'].get('group')
  45. group = self.scope['url_route']['kwargs'].get('group')
  46. username = self.scope['url_route']['kwargs'].get('username')
  47. obj = models.UserInfo.objects.get(username=username)
  48. # text = event['message']['text']
  49. chart_obj = models.Chart_Record_all.objects.create(chart_num=group, username=obj, text=text)
  50. async_to_sync(self.channel_layer.group_send)(group,
  51. # type:触发的函数名称
  52. {'type': 'chart.room',
  53. 'message': {'message': message, 'chart_obj': chart_obj}})
  54. def chart_room(self, event):
  55. """
  56. 群聊
  57. :return:
  58. """
  59. # print('--------->', event['message'])
  60. # 获取组号及发言人
  61. # group = self.scope['url_route']['kwargs'].get('group')
  62. # username = self.scope['url_route']['kwargs'].get('username')
  63. # obj = models.UserInfo.objects.get(username=username)
  64. # text = event['message']['text']
  65. # chart_obj = models.Chart_Record_all.objects.create(chart_num=group, username=obj, text=text)
  66. chart_obj = event['message']['chart_obj']
  67. if chart_obj.username:
  68. # 给所有人回复
  69. self.send(
  70. json.dumps(
  71. {'username': chart_obj.username.username, 'text': chart_obj.text,
  72. 'timer': str(chart_obj.create_time)[0:19]},
  73. ensure_ascii=False))
  74. # 当客户端/服务端主动断开连接自动触发
  75. def websocket_disconnect(self, message):
  76. group = self.scope['url_route']['kwargs'].get('group')
  77. print('客户端主动断开连接了')
  78. # 可以让websocket_disconnect函数不执行
  79. # 群聊断开
  80. async_to_sync(self.channel_layer.group_discard)(group, self.channel_name) # self.channel_name当前名字
  81. raise StopConsumer()

前端

  1. <script>
  2. socket = new WebSocket("ws://127.0.0.1:8000/all_chart/{{ room_id }}/{{ username }}/")
  3. // 1.发送数据
  4. $("#send").click(function () {
  5. let mess = $('#txt').val()
  6. socket.send(mess)
  7. $('#txt').val('')
  8. })
  9. // 2.接收服务端返回的数据
  10. socket.onmessage = function (event) {
  11. {#console.log(event.data)#}
  12. var data = JSON.parse(event.data)
  13. // event.data 返回的数据
  14. // 创建标签
  15. var cn_div = $("<div>").attr('class', 'conversation-name')
  16. var mb_p = $("<p>").attr('class', 'mb-0').text(data.text)
  17. var ctec_div = $("<div>").attr('class', 'ctext-wrap-content').append(mb_p)
  18. var cte_div = $("<div>").attr('class', 'ctext-wrap').append(ctec_div)
  19. var user_div = $("<div>").attr('class', 'user-chat-content').append(cte_div).append(data.username + ' ' + '发言时间:' + data.timer)
  20. var con_div = $("<div>").attr('class', 'conversation-list').append(user_div)
  21. var li = $("<li>").append(con_div)
  22. // 获取ul
  23. $("#old_ul").append(li)
  24. //添加文本数据到标签里面
  25. }
  26. //3 客户端连接服务端成功之后自动触发 self.accept()成功之后
  27. socket.onopen = function (event) {
  28. {#// 创建标签#}
  29. {#var link = $("<div>")#}
  30. {#// 获取message#}
  31. {#let message = $("#message")#}
  32. {#link.html("连接成功")#}
  33. {##}
  34. {#//添加文本数据到标签里面#}
  35. {#message.append(link)#}
  36. }
  37. </script>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/327503
推荐阅读
相关标签
  

闽ICP备14008679号