06.websocket
# 01.websocket
websocket:https://www.cnblogs.com/xiaonq/p/12238651.html
webssh:https://www.cnblogs.com/xiaonq/p/12243024.html
# 2.websocket(3w1h)
- 什么是websocket
- webSocket是一种在单个TCP连接上进行全双工通信的协议
- 客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
- 浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输
- websocket与http区别
- http请求建立连接只能发送一次请求,不能有服务器端主动向客户端发送请求
- websocket建立的长连接,一次连接,后续一直通信,这样节省资源,可以有客户端发送请求给服务器端
- 远古时期解决方案就是轮询
- 客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动(浪费流量和资源)
- webSocket应用场景?
- **聊天软件:**最著名的就是微信,QQ,这一类社交聊天的app
- **弹幕:**各种直播的弹幕窗口
- **在线教育:**可以视频聊天、即时聊天以及其与别人合作一起在网上讨论问题…
- websocket原理
- websocket首先借助http协议(通过在http头部设置属性,请求和服务器进行协议升级,升级协议为websocket的应用层协议)
- 建立好和服务器之间的数据流,数据流之间底层还是依靠TCP协议;
- websocket会接着使用这条建立好的数据流和服务器之间保持通信;
- 由于复杂的网络环境,数据流可能会断开,在实际使用过程中,我们在onFailure或者onClosing回调方法中,实现重连
- websocket实现心跳检测的思路
- 通过setInterval定时任务每个3秒钟调用一次reconnect函数
- reconnect会通过socket.readyState来判断这个websocket连接是否正常
- 如果不正常就会触发定时连接,每4s钟重试一次,直到连接成功
- 如果是网络断开的情况下,在指定的时间内服务器端并没有返回心跳响应消息,因此服务器端断开了。
- 服务断开我们使用ws.close关闭连接,在一段时间后,可以通过 onclose事件监听到。
- 实现聊天功能
# 后端的django代码
from django.shortcuts import render
from dwebsocket.decorators import accept_websocket,require_websocket
from django.http import HttpResponse
def index(request):
return render(request, 'index.html')
from dwebsocket.backends.default.websocket import DefaultWebSocket # request.websocket就是DefaultWebSocket对象
tmp = []
# 只有加了这个装饰器,这个视图函数才能处理websocket请求
@accept_websocket
def echo(request):
if not request.is_websocket(): #判断是不是websocket连接
try: #如果是普通的http方法
message = request.GET['message']
return HttpResponse(message)
except:
return render(request,'index.html')
else:
'''1.实现消息推送'''
tmp.append(request.websocket) # 把所有连接的websocket连接都加入列表中
# request.websocket = <dwebsocket.backends.default.websocket.DefaultWebSocket object at 0x00000272E69A4320>
# failed:Invalid frame header:你的视图没有阻塞,请求过一次后服务器端就关闭连接了
# 所以使用for循环 request.websocket 对象就会调用 __iter__()方法,利用迭代器进行阻塞
for message in request.websocket:
for ws in tmp:
ws.send(message)
'''2.实现聊天室思路'''
# d = {} # 使用了一个dict来保存数据,
# d['zhangsan'] = request.websocket # key值是用户身份,value值是dict类型的{username:websocket}。
# d['zhangsan'].send(message) # 发送消息到客户端
# d['lisi'].send(message) ==> request.websocket.send(message)
# 这只是个思路,如果正式使用的话,肯定会对group封装,也不会只保存在内存中,需要保存到redis中去
# 并且对每个websocket对象设置有效期,过期清除,避免长期挂起状态消耗系统资源等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 前端VUE代码
<template>
<div>
<button @click="send">发消息</button>
</div>
</template>
<script>
export default {
data () {
return {
path:"ws://127.0.0.1:8000/echo?username=zhangsan&token=xxxx",
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 () {
var params = 'hahahahhahaha';
this.socket.send(params) // 发送给后台的数据
},
close: function () {
console.log("socket已经关闭")
}
},
destroyed () {
// 销毁监听
this.socket.onclose = this.close
}
}
</script>
<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
上次更新: 2024/10/15 16:27:13