一、Websockets介绍

随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。
 
我们知道,传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如
浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式

对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应

用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。
  轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。
 

Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。
  这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。
 

伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。WebSocket的工作流程是这
样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过

TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小了很多.

关于websocket的优点可以看:http://www.tuicool.com/articles/7zyMvy6

二,Python中的WebSocket

 Django的WebSocket:

  1.dwebsocket:  https://www.cnblogs.com/huguodong/p/6611602.html

  2.channels:  http://www.cnblogs.com/evilliu/articles/6529087.html

参考链接:https://www.cnblogs.com/jingmoxukong/p/7755643.html

这里使用flask作为服务器,python版本为3.6.5

安装模块

pip install gevent-websocket

群聊

from flask import Flask,request,render_template
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from geventwebsocket.websocket import WebSocket
import json app = Flask(__name__) user_dict = {} # 空字典,用来存放用户名和发送消息 @app.route("/<username>") # 参数为用户名
def index(username):
# 获取请求的WebSocket对象
user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
if user_socket:
# 设置键值对
# {'xiao': <geventwebsocket.websocket.WebSocket object at 0x0000020F6F6B8DB0>}
user_dict[username] = user_socket
print(user_dict) # 循环,接收消息
while True:
# 接收消息
msg = user_socket.receive()
print(msg)
# 反序列化数据,因为前端发送的是json
recv_msg = json.loads(msg)
print(recv_msg)
# 构造数据结构
send_msg = {
# 获取用户名
"username":recv_msg.get("username"),
# 获取消息
"msg":recv_msg.get("msg")
}
# 遍历字典
for i in user_dict.values():
# 这里的i就是websocket对象
# 判断websocket对象等于请求的websocket对象
if i == user_socket:
# 跳过循环
continue # 发送数据,对数据做序列化
i.send(json.dumps(send_msg)) @app.route("/ws")
def ws():
return render_template("many_people.html") if __name__ == '__main__':
# 创建一个WebSocket服务器
http_serv = WSGIServer(("0.0.0.0",),app,handler_class=WebSocketHandler)
# 开始监听HTTP请求
http_serv.serve_forever()
# app.run("0.0.0.0", , debug=True)

前端

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> </head>
<body>
你的昵称:<input type="text" id="nickname">
<button onclick="connws()">连接服务器</button>
<br><br>
发送消息:<input type="text" id="talk">
<button onclick="send_msg()">发送信息</button><br><br>
<div style="width: 500px;height: 100%;border: 1px red solid;" id="text"> </div>
</body>
<script type="application/javascript">
var user_name = null; //用户名
var ws = null; //WebSocket 对象,默认设置为空 //连接ws
function connws() {
//获取输入框中的用户名
user_name = document.getElementById("nickname").value;
//创建 WebSocket 对象
ws = new WebSocket("ws://127.0.0.1:5000/" + user_name);
//客户端接收服务端数据时触发
ws.onmessage = function (data) {
// 反序列化接收数据
var recv_msg = JSON.parse(data.data);
console.log(recv_msg);
// 执行自定义函数createDiv,传入2个参数
createDiv(recv_msg.username, recv_msg.msg);
};
} //发送消息
function send_msg() {
// 获取输入框的发送消息
var talk = document.getElementById("talk").value;
// 执行自定义函数createDiv
createDiv("w", talk);
// 组件发送数据对象
send_str = {
username:user_name, //用户名
msg:talk //消息
};
//使用连接发送数据,序列化对象
ws.send(JSON.stringify(send_str));
}; //显示聊天信息
function createDiv(self, content) {
// 创建div标签
var divtag = document.createElement("div");
//定义格式
var who = self + " : ";
// 判断参数为w时
if (self == "w") {
// 替换字符串
who = "我 : "
}
// 修改显示框的text属性
divtag.innerText = who + content;
// 获取显示框
var text = document.getElementById("text");
// appendChild() 方法向节点添加最后一个子节点
// 添加一个div标签
text.appendChild(divtag);
} </script>
</html>

单聊

from flask import Flask,request,render_template
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from geventwebsocket.websocket import WebSocket
import json app = Flask(__name__) user_dict = {} # 空字典,用来存放用户名和发送消息 @app.route("/<username>") # 参数为用户名
def index(username):
# 获取请求的WebSocket对象
user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
if user_socket:
# 设置键值对
# {'xiao': <geventwebsocket.websocket.WebSocket object at 0x0000020F6F6B8DB0>}
user_dict[username] = user_socket
print(user_dict) # 循环,接收消息
while True:
# 接收消息
msg = user_socket.receive()
# print(msg)
# 反序列化数据,因为前端发送的是json
recv_msg = json.loads(msg)
print(recv_msg)
# 构造数据结构
send_msg = {
# 消息
"msg": recv_msg.get("msg"),
# 来自于哪个用户
"from_user": username,
}
# 获取聊天对象的名字
to_user = user_dict.get(recv_msg.get("to_user"))
# 发送数据
to_user.send(json.dumps(send_msg)) @app.route("/ws")
def ws():
return render_template("single_chat.html") if __name__ == '__main__':
# 创建一个WebSocket服务器
http_serv = WSGIServer(("0.0.0.0",5000),app,handler_class=WebSocketHandler)
# 开始监听HTTP请求
http_serv.serve_forever()
# app.run("0.0.0.0", 5000, debug=True)

后端

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> </head>
<body>
你的昵称:<input type="text" id="nickname">
<button onclick="connws()">连接服务器</button>
<br>
与谁说话:<input type="text" id="sender">
<br>
发送消息:<input type="text" id="talk">
<button onclick="send_msg()">发送信息</button><br/><br/>
<div style="width: 500px;height: 100%;border: 1px red solid;" id="text"> </div>
</body>
<script type="application/javascript">
var user_name = null; //用户名
var ws = null; //WebSocket 对象,默认设置为空 //连接ws
function connws() {
//获取输入框中的用户名
user_name = document.getElementById("nickname").value;
//创建 WebSocket 对象
ws = new WebSocket("ws://127.0.0.1:5000/" + user_name);
//客户端接收服务端数据时触发
ws.onmessage = function (data) {
// 反序列化接收数据
var recv_msg = JSON.parse(data.data);
console.log(recv_msg);
// 执行自定义函数createDiv,传入2个参数
createDiv(recv_msg.from_user, recv_msg.msg);
};
} function send_msg() {
// 获取输入框的发送消息
var talk = document.getElementById("talk").value;
// 获取输入框的聊天对象
var sender = document.getElementById("sender").value;
// 执行自定义函数createDiv
createDiv("w", talk);
// 构造发送数据对象
send_str = {
msg:talk, //消息
to_user:sender, //对方
};
//使用连接发送数据,序列化对象
ws.send(JSON.stringify(send_str));
}; //显示聊天信息
function createDiv(self, content) {
// 创建div标签
var divtag = document.createElement("div");
//定义格式
var who = self + " : ";
// 判断参数为w时
if (self == "w") {
// 替换字符串
who = "我 : "
}
// 修改显示框的text属性
divtag.innerText = who + content;
// 获取显示框
var text = document.getElementById("text");
// appendChild() 方法向节点添加最后一个子节点
// 添加一个div标签
text.appendChild(divtag);
} </script>
</html>

前端

相关拓展:https://segmentfault.com/a/1190000010140660

Python中的WebSocket的更多相关文章

  1. python测试基于websocket协议的即时通讯接口

    随着html5的广泛应用,基于websocket协议的即时通讯有了越来越多的使用场景,本文使用python中的websocket-client模块来做相关的接口测试 import webclient ...

  2. [转]Python中的str与unicode处理方法

    早上被python的编码搞得抓耳挠腮,在搜资料的时候感觉这篇博文很不错,所以收藏在此. python2.x中处理中文,是一件头疼的事情.网上写这方面的文章,测次不齐,而且都会有点错误,所以在这里打算自 ...

  3. python中的Ellipsis

    ...在python中居然是个常量 print(...) # Ellipsis 看别人怎么装逼 https://www.keakon.net/2014/12/05/Python%E8%A3%85%E9 ...

  4. python中的默认参数

    https://eastlakeside.gitbooks.io/interpy-zh/content/Mutation/ 看下面的代码 def add_to(num, target=[]): tar ...

  5. Python中的类、对象、继承

    类 Python中,类的命名使用帕斯卡命名方式,即首字母大写. Python中定义类的方式如下: class 类名([父类名[,父类名[,...]]]): pass 省略父类名表示该类直接继承自obj ...

  6. python中的TypeError错误解决办法

    新手在学习python时候,会遇到很多的坑,下面来具体说说其中一个. 在使用python编写面向对象的程序时,新手可能遇到TypeError: this constructor takes no ar ...

  7. python中的迭代、生成器等等

    本人对编程语言实在是一窍不通啊...今天看了廖雪峰老师的关于迭代,迭代器,生成器,递归等等,word天,这都什么跟什么啊... 1.关于迭代 如果给定一个list或tuple,我们可以通过for循环来 ...

  8. python2.7高级编程 笔记二(Python中的描述符)

    Python中包含了许多内建的语言特性,它们使得代码简洁且易于理解.这些特性包括列表/集合/字典推导式,属性(property).以及装饰器(decorator).对于大部分特性来说,这些" ...

  9. python cookbook 学习系列(一) python中的装饰器

    简介 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓 ...

随机推荐

  1. The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Cha

    The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Cha ...

  2. php在linux中执行外部命令

    目录:一.PHP中调用外部命令介绍二.关于安全问题三.关于超时问题四.关于PHP运行linux环境中命令出现的问题 一.PHP中调用外部命令介绍在PHP中调用外部命令,可以用,1>调用专门函数. ...

  3. 【python】map list for 运行时长测试

    import time,sys reps=1000 size=10000 def tester(func,*args): starttime=time.time() for i in range(re ...

  4. Laravel5.1 分页展示

    Laravel为我们提供了一套分页的逻辑,我们无需自己实现分页逻辑,只需要执行几个简单的方法就能实现漂亮的分页. 1 simplePaginate 这是一种只显示上一页下一页的样式分页,我们来看看怎么 ...

  5. linux jdk 6 版本下载

    http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase6-41940 ...

  6. 160622、详解JavaScript变量提升

    变量在程序中随处可见.它们是一些始终在相互影响,相互作用的的数据和逻辑.正是这些互动使应用程序活了起来. 在JavaScript中使用变量很重要的一方面就是变量的提升 —— 它决定了一个变量何时可以被 ...

  7. mysql数据库表卡死怎么办

    -  解决思路就是找到等待的线程并kill -- 查看所有进程 1.SHOW PROCESSLIST; 2.找到卡死或在等待的线程,kill,假设这里是49496卡死了 KILL 49496;

  8. delphi 遇到问题、报错等

    解决方法:using Windows

  9. kafka_2.11-0.10.1.1集群搭建安装配置

    在搭建kafka集群之前,请保证zookeeper已安装. 1.下载 官网下载链接:http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/0.10.1.1/ ...

  10. Python菜鸟之路:原生Ajax/Jquery Ajax/IFrame Ajax的选用

    原生Ajax Jquery Ajax IFrame Ajax 如果发送的是普通的数据,比如用户简单的输入.选择的值,推荐使用Jquery ,其次用XMLHttpRquest对象,最次使用IFrame ...