WebSocket长连接
1、概述
1.1 定义
1.2 原理
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**
-
基于asgi/channels启动
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("不要回答,不要回答,不要回答")
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
-
方法一
<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>