一、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

安装模块

  1. pip install gevent-websocket

群聊

  1. from flask import Flask,request,render_template
  2. from geventwebsocket.handler import WebSocketHandler
  3. from gevent.pywsgi import WSGIServer
  4. from geventwebsocket.websocket import WebSocket
  5. import json
  6.  
  7. app = Flask(__name__)
  8.  
  9. user_dict = {} # 空字典,用来存放用户名和发送消息
  10.  
  11. @app.route("/<username>") # 参数为用户名
  12. def index(username):
  13. # 获取请求的WebSocket对象
  14. user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
  15. if user_socket:
  16. # 设置键值对
  17. # {'xiao': <geventwebsocket.websocket.WebSocket object at 0x0000020F6F6B8DB0>}
  18. user_dict[username] = user_socket
  19. print(user_dict)
  20.  
  21. # 循环,接收消息
  22. while True:
  23. # 接收消息
  24. msg = user_socket.receive()
  25. print(msg)
  26. # 反序列化数据,因为前端发送的是json
  27. recv_msg = json.loads(msg)
  28. print(recv_msg)
  29. # 构造数据结构
  30. send_msg = {
  31. # 获取用户名
  32. "username":recv_msg.get("username"),
  33. # 获取消息
  34. "msg":recv_msg.get("msg")
  35. }
  36. # 遍历字典
  37. for i in user_dict.values():
  38. # 这里的i就是websocket对象
  39. # 判断websocket对象等于请求的websocket对象
  40. if i == user_socket:
  41. # 跳过循环
  42. continue
  43.  
  44. # 发送数据,对数据做序列化
  45. i.send(json.dumps(send_msg))
  46.  
  47. @app.route("/ws")
  48. def ws():
  49. return render_template("many_people.html")
  50.  
  51. if __name__ == '__main__':
  52. # 创建一个WebSocket服务器
  53. http_serv = WSGIServer(("0.0.0.0",),app,handler_class=WebSocketHandler)
  54. # 开始监听HTTP请求
  55. http_serv.serve_forever()
  56. # app.run("0.0.0.0", , debug=True)

前端

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6.  
  7. </head>
  8. <body>
  9. 你的昵称:<input type="text" id="nickname">
  10. <button onclick="connws()">连接服务器</button>
  11. <br><br>
  12. 发送消息:<input type="text" id="talk">
  13. <button onclick="send_msg()">发送信息</button><br><br>
  14. <div style="width: 500px;height: 100%;border: 1px red solid;" id="text">
  15.  
  16. </div>
  17. </body>
  18. <script type="application/javascript">
  19. var user_name = null; //用户名
  20. var ws = null; //WebSocket 对象,默认设置为空
  21.  
  22. //连接ws
  23. function connws() {
  24. //获取输入框中的用户名
  25. user_name = document.getElementById("nickname").value;
  26. //创建 WebSocket 对象
  27. ws = new WebSocket("ws://127.0.0.1:5000/" + user_name);
  28. //客户端接收服务端数据时触发
  29. ws.onmessage = function (data) {
  30. // 反序列化接收数据
  31. var recv_msg = JSON.parse(data.data);
  32. console.log(recv_msg);
  33. // 执行自定义函数createDiv,传入2个参数
  34. createDiv(recv_msg.username, recv_msg.msg);
  35. };
  36. }
  37.  
  38. //发送消息
  39. function send_msg() {
  40. // 获取输入框的发送消息
  41. var talk = document.getElementById("talk").value;
  42. // 执行自定义函数createDiv
  43. createDiv("w", talk);
  44. // 组件发送数据对象
  45. send_str = {
  46. username:user_name, //用户名
  47. msg:talk //消息
  48. };
  49. //使用连接发送数据,序列化对象
  50. ws.send(JSON.stringify(send_str));
  51. };
  52.  
  53. //显示聊天信息
  54. function createDiv(self, content) {
  55. // 创建div标签
  56. var divtag = document.createElement("div");
  57. //定义格式
  58. var who = self + " : ";
  59. // 判断参数为w时
  60. if (self == "w") {
  61. // 替换字符串
  62. who = "我 : "
  63. }
  64. // 修改显示框的text属性
  65. divtag.innerText = who + content;
  66. // 获取显示框
  67. var text = document.getElementById("text");
  68. // appendChild() 方法向节点添加最后一个子节点
  69. // 添加一个div标签
  70. text.appendChild(divtag);
  71. }
  72.  
  73. </script>
  74. </html>

单聊

  1. from flask import Flask,request,render_template
  2. from geventwebsocket.handler import WebSocketHandler
  3. from gevent.pywsgi import WSGIServer
  4. from geventwebsocket.websocket import WebSocket
  5. import json
  6.  
  7. app = Flask(__name__)
  8.  
  9. user_dict = {} # 空字典,用来存放用户名和发送消息
  10.  
  11. @app.route("/<username>") # 参数为用户名
  12. def index(username):
  13. # 获取请求的WebSocket对象
  14. user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
  15. if user_socket:
  16. # 设置键值对
  17. # {'xiao': <geventwebsocket.websocket.WebSocket object at 0x0000020F6F6B8DB0>}
  18. user_dict[username] = user_socket
  19. print(user_dict)
  20.  
  21. # 循环,接收消息
  22. while True:
  23. # 接收消息
  24. msg = user_socket.receive()
  25. # print(msg)
  26. # 反序列化数据,因为前端发送的是json
  27. recv_msg = json.loads(msg)
  28. print(recv_msg)
  29. # 构造数据结构
  30. send_msg = {
  31. # 消息
  32. "msg": recv_msg.get("msg"),
  33. # 来自于哪个用户
  34. "from_user": username,
  35. }
  36. # 获取聊天对象的名字
  37. to_user = user_dict.get(recv_msg.get("to_user"))
  38. # 发送数据
  39. to_user.send(json.dumps(send_msg))
  40.  
  41. @app.route("/ws")
  42. def ws():
  43. return render_template("single_chat.html")
  44.  
  45. if __name__ == '__main__':
  46. # 创建一个WebSocket服务器
  47. http_serv = WSGIServer(("0.0.0.0",5000),app,handler_class=WebSocketHandler)
  48. # 开始监听HTTP请求
  49. http_serv.serve_forever()
  50. # app.run("0.0.0.0", 5000, debug=True)

后端

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6.  
  7. </head>
  8. <body>
  9. 你的昵称:<input type="text" id="nickname">
  10. <button onclick="connws()">连接服务器</button>
  11. <br>
  12. 与谁说话:<input type="text" id="sender">
  13. <br>
  14. 发送消息:<input type="text" id="talk">
  15. <button onclick="send_msg()">发送信息</button><br/><br/>
  16. <div style="width: 500px;height: 100%;border: 1px red solid;" id="text">
  17.  
  18. </div>
  19. </body>
  20. <script type="application/javascript">
  21. var user_name = null; //用户名
  22. var ws = null; //WebSocket 对象,默认设置为空
  23.  
  24. //连接ws
  25. function connws() {
  26. //获取输入框中的用户名
  27. user_name = document.getElementById("nickname").value;
  28. //创建 WebSocket 对象
  29. ws = new WebSocket("ws://127.0.0.1:5000/" + user_name);
  30. //客户端接收服务端数据时触发
  31. ws.onmessage = function (data) {
  32. // 反序列化接收数据
  33. var recv_msg = JSON.parse(data.data);
  34. console.log(recv_msg);
  35. // 执行自定义函数createDiv,传入2个参数
  36. createDiv(recv_msg.from_user, recv_msg.msg);
  37. };
  38. }
  39.  
  40. function send_msg() {
  41. // 获取输入框的发送消息
  42. var talk = document.getElementById("talk").value;
  43. // 获取输入框的聊天对象
  44. var sender = document.getElementById("sender").value;
  45. // 执行自定义函数createDiv
  46. createDiv("w", talk);
  47. // 构造发送数据对象
  48. send_str = {
  49. msg:talk, //消息
  50. to_user:sender, //对方
  51. };
  52. //使用连接发送数据,序列化对象
  53. ws.send(JSON.stringify(send_str));
  54. };
  55.  
  56. //显示聊天信息
  57. function createDiv(self, content) {
  58. // 创建div标签
  59. var divtag = document.createElement("div");
  60. //定义格式
  61. var who = self + " : ";
  62. // 判断参数为w时
  63. if (self == "w") {
  64. // 替换字符串
  65. who = "我 : "
  66. }
  67. // 修改显示框的text属性
  68. divtag.innerText = who + content;
  69. // 获取显示框
  70. var text = document.getElementById("text");
  71. // appendChild() 方法向节点添加最后一个子节点
  72. // 添加一个div标签
  73. text.appendChild(divtag);
  74. }
  75.  
  76. </script>
  77. </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. Extjs5 app.js缓冲设置

    在6月2日Extjs5正式版公布后.粗略研究了一下,sencha推荐使用project编译来公布应用.开发过程中用sencha app watch命令就可以生成服务.每建立一个js类,就须要Ctrl+ ...

  2. 【ARDUINO】蓝牙(HC-05)透传

    1.蓝牙连接ARDUINO 工作模式:VCC-5.5V GND-GND TXD-RX RXD-TX  工作模式下默认波特率38400 AT模式,在工作模式的基础上KEY-VCC/5.5V 设置从模式: ...

  3. VS2010程序打包操作(结合图片详细讲解)

     附视频教程:http://www.cnblogs.com/mengdesen/archive/2011/06/14/2080312.html 1.  在vs2010 选择“新建项目”----“其他项 ...

  4. script跨域之360搜索

    思考: 布局: 1,flex元素上下左右居中,内部元素横向排列: div{ /* 100vh = viewport height*/ display: flex; justify-content: c ...

  5. 【BZOJ4711】小奇挖矿 树形DP

    [BZOJ4711]小奇挖矿 Description [题目背景] 小奇在喵星系使用了无限非概率驱动的采矿机,以至于在所有星球上都采出了一些矿石,现在它准备建一些矿石仓库并把矿石运到各个仓库里. [问 ...

  6. 【BZOJ4260】Codechef REBXOR Trie树+贪心

    [BZOJ4260]Codechef REBXOR Description Input 输入数据的第一行包含一个整数N,表示数组中的元素个数. 第二行包含N个整数A1,A2,…,AN. Output ...

  7. 爬虫实战【12】使用cookie登陆豆瓣电影以及获取单个电影的所有短评

    昨天我们已经实现了如何抓取豆瓣上的热门电影信息,虽然不多,只有几百,但是足够我们进行分析了. 今天我们来讲一下如何获取某一部电影的所有短评论信息,并保存到mongodb中. 反爬虫 豆瓣设置的反爬虫机 ...

  8. 【Git和GitHub】学习笔记

    1. 书籍推荐: 先看一本比较简单并且好的入门书籍 Git - Book https://git-scm.com/book/zh/v2 2. 书籍理解: Git 有三种状态,你的文件可能处于其中之一: ...

  9. XML 解析之 dom4j 解析器

    dom4j 的使用需要导入 jar 包, 包括: dom4j-1.6.1 和 jaxen-1.1-beta 步骤: 在项目目录下,"Folder" 创建一个 lib 文件夹 复制 ...

  10. 细数Python中的数据类型以及他们的方法

    一.数据类型的种类及主要功能 1.数字类型 数字类型主要是用来计算,它分为整数类型int和浮点类型float 2.布尔类型 布尔类型主要是用于判断,它分为真True和False两种 3.字符串类型 字 ...