WebSocke实时通讯协议
WebSocket 是什么?
WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
为什么需要 WebSocket ?
了解计算机网络协议的人,应该都知道:HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步JavaScript和XML(AJAX)请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。
WebSocket 如何工作?
Web浏览器和服务器都必须实现 WebSockets 协议来建立和维护连接。由于 WebSockets 连接长期存在,与典型的HTTP连接不同,对服务器有重要的影响。
基于多线程或多进程的服务器无法适用于 WebSockets,因为它旨在打开连接,尽可能快地处理请求,然后关闭连接。任何实际的 WebSockets 服务器端实现都需要一个异步服务器。
-服务端(socket服务器)
1.服务器开启socket,监听ip和端口
3.允许连接
* 5.服务端收到特殊值【特殊值加密sha1,migic string="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"】
* 6.加密后的值发送给客户端
-客户端(浏览器)
2.客户端发起连接请求(ip和端口)
* 4.客户端生成一个随机字符串xxx,【特殊值加密sha1,migic string="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"】,向服务端发送一段特殊值
* 7.客户端收到加密的值
***收发数据***
"""
1.位运算,右移动
10010001
右4
00001001
左4
100100010000
2.异或运算
1,1:1
0,1 :0
0,0 :0
查看某个数的后四位
10001010
00001111
00001010
info = b'\x81\x8b\xc9\x11\x81b\xa1t\xed\x0e\xa61\xf6\r\xbb}\xe5'
opcode = info[0] & 15 获取第一个字节的后四位
fin = info[0] >> 7
payload_len = info[1] & 127
if payload_len<126:
头部占2个字节
elif payload_len == 126:
头部占4个字节
else:
头部占10个字节
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+------------------------------------------------------------
WebSocket 客户端
在客户端,没有必要为 WebSockets 使用 JavaScript 库。实现 WebSockets 的 Web 浏览器将通过 WebSockets 对象公开所有必需的客户端功能(主要指支持 Html5 的浏览器)。
客户端 API
以下 API 用于创建 WebSocket 对象。
因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。
var Socket = new WebSocket(url, [protocol] );
WebSocket 属性
以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:

WebSocket 事件
以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:

WebSocket 方法
以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:

示例一:websocket+tornado实现聊天室
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
background-color: black;
}
.container{
border:2px solid #dddddd;
height: 400px;
overflow: auto;
}
</style>
</head>
<body>
<div style="width: 750px;margin: 0 auto;">">
<h1 style="">">1024聊天室</h1>
<div class="container"></div>
<div class="input">
<input class="name" style="width: 50px;height: 15px;" type="text" value="游客">
<input type="text" id="txt">
<input type="button" id="btn" value="发送" onclick="sendMessage()">
<input type="button" id="close" value="关闭连接" onclick="closeConn()"/>
</div>
<div id="content"></div>
</div>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
$(function () {
wsUpdater.start();
});
var wsUpdater = {
socket: null,
name: null,
start: function() {
var url = "ws://127.0.0.1:8888/chat";
wsUpdater.socket = new WebSocket(url);
wsUpdater.socket.onopen = function () {
/* 与服务器端连接成功后,自动执行 */
var newTag = document.createElement('div');
newTag.innerHTML = "【连接成功】";
document.getElementById('content').appendChild(newTag);
};
wsUpdater.socket.onmessage = function(event) {
console.log(event);
if(wsUpdater.name){
wsUpdater.showMessage(event.data);
}else{
wsUpdater.name = event.data;
}
}
},
showMessage: function(content) {
$('.container').append(content);
}
};
function closeConn() {
/* 服务器端主动断开连接时,自动执行 */
if (confirm("您确定要关闭本页吗?")){
// 旧方法
{#window.opener=null;#}
{#window.open('','_self');#}
{#window.close();#}
// 新方法
window.location.href="about:blank";
window.close();
}
else{}
};
$("#txt").keydown(function (e) {//当按下按键时
if (e.which == 13) {//.which属性判断按下的是哪个键,回车键的键位序号为13
$('#btn').trigger("click");//触发搜索按钮的点击事件
}
});
function sendMessage() {
var msg = {
name:$(".name").val(),
message: $("#txt").val()
};
wsUpdater.socket.send(JSON.stringify(msg));
}
</script>
</body>
</html>
# -*- coding: utf-8 -*-
"""
@Datetime: 2018/8/28
@Author: Zhang Yafei
"""
import json
import uuid
import tornado.web
import tornado.ioloop
import tornado.websocket
class IndexHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render('index.html')
class ChatHandler(tornado.websocket.WebSocketHandler):
users = set()
messages = []
def open(self, *args, **kwargs):
"""
客户端和服务器已经建立连接
1.连接
2.握手
:param args:
:param kwargs:
:return:
"""
ChatHandler.users.add(self)
# uid = str(uuid.uuid4())
# self.write_message(uid)
# for msg in ChatHandler.messages:
# content = self.render_string('message.html', **msg)
# self.write_message(content)
def on_message(self, message):
msg = json.loads(message)
ChatHandler.messages.append(message)
for client in ChatHandler.users:
content = self.render_string('message.html',**msg)
client.write_message(content)
def on_close(self):
"""
客户端主动关闭连接
:return:
"""
ChatHandler.users.remove(self)
def run():
settings = {
'template_path': 'templates',
'static_path': 'static',
}
application = tornado.web.Application([
(r"/", IndexHandler),
(r"/chat", ChatHandler),
], **settings)
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
run()
1024聊天室效果图

示例二:websocket+flask实现实时投票系统
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<title>投票系统</title>
<!-- Bootstrap core CSS -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<link href="static/css/ie10-viewport-bug-workaround.css" rel="stylesheet">
<link href="static/plugins/font-awesome-4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="static/css/dashboard.css" rel="stylesheet">
<script src="static/js/ie-emulation-modes-warning.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">投票系统</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a class="item" href="#">消息<i style="margin-left: 3px;" class="fa fa-bell-o"
aria-hidden="true"></i> <span class="badge"
style="">">4</span></a>
</li>
<li><a class="item" href="#">通知<i style="margin-left: 3px;" class="fa fa-envelope-o"
aria-hidden="true"></i> <span class="badge"
style="">">4</span></a>
</li>
<li><a class="item" href="#">任务<i style="margin-left: 3px;" class="fa fa-commenting-o"
aria-hidden="true"></i> <span class="badge"
style="">">4</span></a>
</li>
<li><a href="https://v3.bootcss.com/examples/dashboard/#"></a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">张亚飞 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人信息</a></li>
<li><a href="#">退出</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control
