• WebSocket长连接


    WebSocket长连接

    1、概述

    image-20211111155015888

    image-20211111155202002

    1.1 定义

    image-20211111160606614

    1.2 原理

    image-20211111162538141

    2、Django中配置WebSocket

    2.1安装第三方法包

    • pip install channels
      

    2.2 Django 中的配置

    • Settings中的配置
      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'app01.apps.App01Config',
          'channels',#注册APP
      ]
      
    • 添加配置
      • 定位到Django3中的asgi.py下的application
      ASGI_APPLICATION = "djangoWS.asgi.application"
      
      • 修改asgy.py文件
      • 默认只支持http协议,修改其内容使得即支持HTTP又要支持WebSocket;
      import os
      
      from django.core.asgi import get_asgi_application
      from channels.routing import ProtocolTypeRouter,URLRouter
      from . import routing
      
      os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoWS.settings')
      # 默认只支持http请求
      # application = get_asgi_application()
      
      application=ProtocolTypeRouter({
          "http":get_asgi_application(),
          "websocket":URLRouter(routing.websocket_urlpatterns),
      })
      
      
    • Settings.py的同级目录下,创建routing.py;

      # -*- coding: utf-8 -*-
      '''
      @Time    : 2021/11/12 9:00
      @Author  : ziqingbaojian
      @File    : routing.py
      '''
      
      from django.urls import re_path
      from app01 import consumers
      
      websocket_urlpatterns=[
          re_path(r'ws/?P<group>\w+/$',consumers.ShowNum.as_asgi())
      ]
      
    • app01下创建consumers.py,编写处理事务的逻辑。

      # -*- coding: utf-8 -*-
      '''
      @Time    : 2021/11/12 9:11
      @Author  : ziqingbaojian
      @File    : consumers.py
      '''
      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      
      # 继承WebsocketConsumer
      class ShowNum(WebsocketConsumer):
          def websocket_connect(self, message):
              # 有客户端来向后端发送WebSocket连接请求时,自动触发
              # 允许客户端的连接
              self.accept()
              # raise StopConsumer()# 不创建连接,直接使用raise将异常抛出;
      
          def websocket_receive(self, message):
              # 基于WebSocket想后端发送数据,自动触发接收数据
              # 接收到前端传回的消息
              self.send("不要回答,不要回答,不要回答")
      
          def websocket_disconnect(self, message):
              # 客户端与服务端断开连接时,自动触发
              raise StopConsumer()
      

    2.3 django中需要了解的

    • wsgi:django3以前django属于同步的,wsgi是处理Socket
    • asgi : 相当于wsgi+异步+WebSocket
    • 普通启动,默认使用的是wsgi**

      image-20211112093454845

    • 基于asgi/channels启动

      image-20211112093744090

    3、聊天室

    • 访问到地址界面,http请求

    • 让客户端向服务端主动发送websocket连接,服务端收到连接后(握手)。

      • 前端
      //websocket的协议,发送数据要带ws相当于,http请求以http开头一样;
      socket= new WebSocket("ws://127.0.0.1:8001/ws/123/")
      
      • 服务端
      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      # 继承WebsocketConsumer
      class ShowNum(WebsocketConsumer):
          def websocket_connect(self, message):
              # 有客户端来向后端发送WebSocket连接请求时,自动触发
              # 允许客户端的连接(握手)
              print("连接来拉")
              self.accept()
              '''两次请求,连接一次握手一次'''
              # raise StopConsumer()# 不创建连接,直接使用raise将异常抛出;
      

    3.1 收发消息( 客户端-->服务端)

    • 客户端
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <style>
              .top{
                  height: 300px;
                   100%;
                  border: 1px solid #ddd;
              }
          </style>
      </head>
      <body>
      <div class="top"></div>
      <input type="text" placeholder="请输入" id="txt">
      <button onclick="sendMessage()">发送</button>
      <script>
          //websocket的协议,发送数据要带ws相当于,http请求以http开头一样;
          socket= new WebSocket("ws://127.0.0.1:8001/ws/123/")
          function sendMessage(){
              var tag=document.getElementById("txt");
              socket.send(tag.value);
          }
      </script>
      </body>
      </html>
      
    • 服务端
      # -*- coding: utf-8 -*-
      '''
      @Time    : 2021/11/12 9:11
      @Author  : ziqingbaojian
      @File    : consumers.py
      '''
      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      # 继承WebsocketConsumer
      class ShowNum(WebsocketConsumer):
      
          def websocket_receive(self, message):
              # 基于WebSocket想后端发送数据,自动触发接收数据
              # 接收到前端传回的消息
              print(message)
              self.send("不要回答,不要回答,不要回答")
      

      image-20211112102841586

    3.2 收发消息(服务端-->客户端)

    • 服务端
      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      
      # 继承WebsocketConsumer
      class ShowNum(WebsocketConsumer):
          def websocket_connect(self, message):
              # 有客户端来向后端发送WebSocket连接请求时,自动触发
              # 允许客户端的连接(握手)
              print("连接来拉")
              self.accept()
              '''两次请求,连接一次握手一次'''
              # raise StopConsumer()# 不创建连接,直接使用raise将异常抛出;
              # 服务端给客户端发送消息
              self.send("来了呀,哈哈哈")
      
      
    • 客户端
      <script>
          //websocket的协议,发送数据要带ws相当于,http请求以http开头一样;
          socket= new WebSocket("ws://127.0.0.1:8001/ws/123/")
          function sendMessage(){
              var tag=document.getElementById("txt");
              socket.send(tag.value);
          }
          //当websocket接收到服务端发送来的消息的时候会自动触发这个函数
          socket.onmessage=function (event){
              console.log(event.data)
          }
          
      </script>
      

    3.2 前端补充回调函数

    <script>
    	//创建好连接之后自动触发(服务端执行完(self.accpet()之后会立即执行)
        socket.onopen=function(event){
            let tag= document.createElement("div");
            tag.innerText="连接成功";
            document.getElementById("top").appendChild(tag);
        }
        //连接成功之后进行提示
    </script>
    

    3.3 关闭连接

    • 客户端主动关闭
      • 客户端
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <style>
              .top{
                  height: 300px;
                   100%;
                  border: 1px solid #ddd;
              }
          </style>
      </head>
      <body>
      <div class="top"></div>
      <input type="text" placeholder="请输入" id="txt">
      <button onclick="sendMessage()">发送</button>
      <button onclick="closeConn()">关闭连接</button>
      
      
      
      <script>
          //websocket的协议,发送数据要带ws相当于,http请求以http开头一样;
          socket= new WebSocket("ws://127.0.0.1:8001/ws/123/")
          function sendMessage(){
              var tag=document.getElementById("txt");
              socket.send(tag.value);
          }
      
          //当websocket接收到服务端发送来的消息的时候会自动触发这个函数
          socket.onmessage=function (event){
              console.log(event.data)
          }
          function closeConn(){
              socket.close();//向服务端发送断开连接的请求
          }
      </script>
      </body>
      </html>
      
      • 服务端
      # -*- coding: utf-8 -*-
      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      # 继承WebsocketConsumer
      class ShowNum(WebsocketConsumer):
      
          def websocket_disconnect(self, message):
              # 客户端与服务端断开连接时,自动触发
              print("断开连接了")
              raise StopConsumer()
      
    • 服务端主动关闭连接
      • 服务端
      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      
      # 继承WebsocketConsumer
      class ShowNum(WebsocketConsumer):
      
      
          def websocket_receive(self, message):
              # 基于WebSocket想后端发送数据,自动触发接收数据
              # 接收到前端传回的消息
              print(message)
              text=message['text']
              print(text)
              self.send("不要回答,不要回答,不要回答")
              if text=="close":
                  # 法一
                  self.close()# 会触发前端的onCllose方法;
                  return # 不在执行后期的代码
                  # 法二
                  # raise StopConsumer()# 如果服务端断开连接时,执行了StopConsumer异常,那么websocket_disconnect方法不在执行;
       
      
      • 客户端
      <script>
          //websocket的协议,发送数据要带ws相当于,http请求以http开头一样;
          socket= new WebSocket("ws://127.0.0.1:8001/ws/123/")
          function sendMessage(){
              var tag=document.getElementById("txt");
              socket.send(tag.value);
          }
          //服务端主动断开连接的时候会被触发
          socket.onclose=function (event){
              console.log("连接已断开")
          }
      </script>
      

    3.4 整合代码示例

    • 服务端
      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      # 继承WebsocketConsumer
      class ShowNum(WebsocketConsumer):
          def websocket_connect(self, message):
              # 有客户端来向后端发送WebSocket连接请求时,自动触发
              # 允许客户端的连接(握手)
              print("连接来拉")
              self.accept()
              '''两次请求,连接一次握手一次'''
              # raise StopConsumer()# 不创建连接,直接使用raise将异常抛出;
              # 服务端给客户端发送消息
              self.send("来了呀,哈哈哈")
      
          def websocket_receive(self, message):
              # 基于WebSocket想后端发送数据,自动触发接收数据
              # 接收到前端传回的消息
              print(message)
              text=message['text']
              print(text)
              self.send("不要回答,不要回答,不要回答")
              if text=="close":
                  # 法一
                  self.close()# 会触发前端的onCllose方法;
                  return # 不在执行后期的代码
                  # 法二
                  # raise StopConsumer()# 如果服务端断开连接时,执行了StopConsumer异常,那么websocket_disconnect方法不在执行;
          def websocket_disconnect(self, message):
              # 客户端与服务端断开连接时,自动触发,包括关闭页面与浏览器的情况
              print("断开连接了")
              raise StopConsumer()
      
    • 客户端
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <style>
              .top{
                  height: 300px;
                   100%;
                  border: 1px solid #ddd;
              }
          </style>
      </head>
      <body>
      <div class="top"></div>
      <input type="text" placeholder="请输入" id="txt">
      <button onclick="sendMessage()">发送</button>
      <button onclick="closeConn()">关闭连接</button>
      <script>
          //websocket的协议,发送数据要带ws相当于,http请求以http开头一样;
          socket= new WebSocket("ws://127.0.0.1:8001/ws/123/")
          function sendMessage(){
              var tag=document.getElementById("txt");
              socket.send(tag.value);
          }
          //服务端主动断开连接的时候会被触发
          socket.onclose=function (event){
              console.log("连接已断开")
          }
      
          //当websocket接收到服务端发送来的消息的时候会自动触发这个函数
          socket.onmessage=function (event){
              console.log(event.data)
          }
          function closeConn(){
              socket.close();//向服务端发送断开连的请求
          }
      </script>
      </body>
      </html>
      

    3.5 群聊功能

    • 配置django中的配置文件或者,自定义设置连接池

    4 、vue中使用Webscoket

    • 参考文献1:https://www.cnblogs.com/niuben/p/14607900.html

    • 参考文献2 :https://www.cnblogs.com/qisi007/p/10213886.html

    • 方法一
      <template>
        <div class="test">
      
        </div>
      </template>
      
      <script>
        export default {
          name : 'test',
          data() {
            return {
              websock: null,
            }
          },
          created() {
            this.initWebSocket();
          },
          destroyed() {
            this.websock.close() //离开路由之后断开websocket连接
          },
          methods: {
            initWebSocket(){ //初始化weosocket
              if()
              const wsuri = "ws://127.0.0.1:8080";
              this.websock = new WebSocket(wsuri);
              this.websock.onmessage = this.websocketonmessage;
              this.websock.onopen = this.websocketonopen;
              this.websock.onerror = this.websocketonerror;
              this.websock.onclose = this.websocketclose;
            },
            websocketonopen(){ //连接建立之后执行send方法发送数据
              let actions = {"test":"12345"};
              this.websocketsend(JSON.stringify(actions));
            },
            websocketonerror(){//连接建立失败重连
              this.initWebSocket();
            },
            websocketonmessage(e){ //数据接收
              const redata = JSON.parse(e.data);
            },
            websocketsend(Data){//数据发送
              this.websock.send(Data);
            },
            websocketclose(e){  //关闭
              console.log('断开连接',e);
            },
          },
        }
      </script>
      <style lang='less'>
       
      </style>
      
      
    • 方法二
      <template>
          <div>
              <button @click="send">发消息</button>
          </div>
      </template>
      
      <script>
      export default {
          data () {
              return {
                  path:"ws://192.168.0.200:8005/qrCodePage/ID=1/refreshTime=5",
                  socket:""
              }
          },
          mounted () {
              // 初始化
              this.init()
          },
          methods: {
              init: function () {
                  if(typeof(WebSocket) === "undefined"){
                      alert("您的浏览器不支持socket")
                  }else{
                      // 实例化socket
                      this.socket = new WebSocket(this.path)
                      // 监听socket连接
                      this.socket.onopen = this.open
                      // 监听socket错误信息
                      this.socket.onerror = this.error
                      // 监听socket消息
                      this.socket.onmessage = this.getMessage
                  }
              },
              open: function () {
                  console.log("socket连接成功")
              },
              error: function () {
                  console.log("连接错误")
              },
              getMessage: function (msg) {
                  console.log(msg.data)
              },
              send: function () {
                  this.socket.send(params)
              },
              close: function () {
                  console.log("socket已经关闭")
              }
          },
          destroyed () {
              // 销毁监听
              this.socket.onclose = this.close
          }
      }
      </script>
      
      <style>
      
      </style>
      
  • 相关阅读:
    nyoj 139 我排第几个--康拓展开
    树形dp--hdu 3534 Tree
    hdu 2196 Computer 树形dp模板题
    poj 2342 Anniversary party 简单树形dp
    hdu 4738 Caocao's Bridges 图--桥的判断模板
    poj 1144 Network 图的割顶判断模板
    poj 3159 Candies 差分约束
    poj 3169 Layout 差分约束模板题
    codeforces C. Triangle
    java中过滤器、监听器、拦截器的区别
  • 原文地址:https://www.cnblogs.com/Blogwj123/p/15674975.html
Copyright © 2020-2023  润新知