首页 > 其他分享 >websocket

websocket

时间:2022-11-18 00:12:32浏览次数:43  
标签:group self websocket message 服务端 客户端

由于http协议无状态,一次请求,一次响应。无法保持持续的连接,而websocket协议可以创建连接持久连续不断的连接,基于这个连接,可以持续收发数据。
常用场景:
web聊天室
实时监控平台,一些图表等。

原理:
建立在http协议之上
--连接,客户端发起
--握手,客户端发送消息,后端接收到消息后再做一些特殊的处理并返回。验证服务端支持websocket协议
在请求头添加几个特殊的请求头
Sec-Websocket-Version
Sec-Websocket-Key
Sec-Websocket-Extensions
服务端接收到后将v1 = Sec-Websocket-Key += magic String进行拼接
拼接完成后,再对拼接后的值进行hmac1加密 v2 = hmac1(Sec-Websocket-Key += magic String)
最后进行base64加密 v3 = base64(v2)
最后再将v3的值返回,放入如下的请求头中
Sec-Websocket-Accept:v3
--收发数据(加密)
b'1213;ddac;32dqf;432r;14q4aff'
--断开连接


----django使用websocket
django默认不支持websocket,需要安装组件channels      --pip install channels==3.0.0  注意如果使用2.0的版本,该配置可能报错
---settings配置
---注册channels 注册到INSTALLED_APPS
--再setting中添加asgi_application
ASGI_APPLICATION = 'websocket_3.asgi.application'
--修改asgi.py文件
--在settings同级目录下创建文件routing.py
--在app03上创建consumer.py文件,并写一个ChatConsumer类,该类必须有以下三个方法
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer

class ChatConsumer(WebsocketConsumer):
def websocket_connect(self,message):
# 有客户端来向服务端发送websocket连接请求,自动触发
self.accept()
#服务端允许和客户端创建连接

def websocket_receive(self,message):
#客户端基于websocket向后端发送数据,自动触发,用于接收客户端传过来的消息
self.send()
#用户向客户端发送消息
self.close()
#服务端主动断开连接
pass

def websocket_disconnect(self,message):
#客户端与服务端断开连接时,自动触发。
pass
def websocket_connect(self,message):
# 有客户端来向服务端发送websocket连接请求,自动触发
self.accept()
#服务端允许和客户端创建连接


-----------------------注意事项-------------------------------------
def websocket_receive(self,message):
#客户端基于websocket向后端发送数据,自动触发,用于接收客户端传过来的消息
self.send()
# #用户向客户端发送消息
# self.close()
# raise StopConsumer()
#如果服务端只单纯的用self.close(),关闭连接。由于是全双工模式,该方式会让两端全部断开,即也会自动执行websocket_disconnect函数
#如果self.close()后面接raise StopConsumer(),只是服务端主动与客户端的连接断开,不会执行websocket_disconnect函数

def websocket_disconnect(self,message):
#客户端与服务端断开连接时,自动触发。
raise StopConsumer()



----聊天室案例
前端
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
    <style>
        .msg{
            height: 500px;
            border: 1px solid #ddd;
            width: 100%;
        }
    </style>
</head>
<body>
    <div class="msg"></div>
    <div>
        <input type="text"   placeholder="请输入" id="text">
        <input type="button" value="发送" onclick="sendMsg();">
    </div>
</body>

<script>
  var socket = new WebSocket("ws://127.0.0.1:8000/room/{{ num }}/");
  //当与服务端建立连接后,自动触发
    socket.onopen = function (event) {
                    var tag = $("<div>");
                    tag.text('连接成功');      //创建一个标签<div></div>
                    $(".msg").append(tag);  //将标签添加到页面
    }
   function sendMsg(){
        var text = $("#text").val();
        socket.send(text)           //利用soket给服务端发送消息
   }
  //回调函数,当服务端给客户端发送消息时,自动触发
    socket.onmessage = function (event) {
        console.log(event.data)     //获取服务端返回的数据
         var tag = $("<div>");
         tag.text(event.data);      //创建一个标签<div></div>
         $(".msg").append(tag);  //将标签添加到页面
         console.log(event.data)
    }
</script>
</html>

后端代码

from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
from asgiref.sync import async_to_sync

class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self,message):
        # 有客户端来向服务端发送websocket连接请求,自动触发
        self.accept()
        #服务端允许和客户端创建连接
        group_num = self.scope['url_route']['kwargs'].get('group')  #获取路由的组名

        print('有人连接到--',group_num)

        async_to_sync(self.channel_layer.group_add)(group_num,self.channel_name)
        #  将与这个客户端连接放入到channel_layer的组里,组名为group_num
    #     channel_layer该方法只支持异步,所以用async_to_sync转为同步写法

    def websocket_receive(self,message):
        print(message)              #返回一个字典
        text = message['text']         #获取发送过来的数据
        group_num = self.scope['url_route']['kwargs'].get('group')  #获取路由的组名
        # 通知组内所有的客户端,执行send_msg方法。我们在此方法中可以定义任何功能
        async_to_sync(self.channel_layer.group_send)(group_num,{'type':'send.msg','message':text})

    def websocket_disconnect(self,message):
        #客户端与服务端断开连接时,自动触发。
        group_num = self.scope['url_route']['kwargs'].get('group')  #获取路由的组名
        print('有人断开连接了---')
        async_to_sync(self.channel_layer.group_discard)(group_num,self.channel_name)
        # 将与该客户端的连接从channel_layer的组中移除
        raise StopConsumer()

    def send_msg(self,msg):
        print(msg)
        text = msg['message']
        self.send(text)          #将消息发送给所有客户端

 

标签:group,self,websocket,message,服务端,客户端
From: https://www.cnblogs.com/powfu/p/16901864.html

相关文章