赞
踩
WebSocket与HTTPS相似,是一种客户端-服务端模型的通信协议。
HTTP carries extra overheard in individual request and response, WebSocket carries the overhead data while placing connection then it carries less or balanced data within individual request-response.
HTTP | WebSocket |
---|---|
Added overhead due to SSL handshake and likewise carries added overhead in individual request-response | Lessor moderate overhead while establishing the connection and less overhead in individual requests |
The client needs to interact with the server via a specific method for communication or transmission of data | WebSocket is bi-directional |
Half-Duplex | Full-Duplex |
Service push is not supported natively, client pulling or download streaming is required | The Service push is base of WebSocket implementation |
socket.io是一个基于WebSocket的CS的实时通信库,它底层基于engine.io。engine.io使用WebSocket和xhr-polling(或jsonp)封装了一套自己的协议,在不支持WebSocket的低版本浏览器中来代替。socket.io在engine.io的基础上增加了namespace,room,自动重连等特性。
在HTTP 协议开发的时候,并不是为了双向通信程序准备的,起初的 web 应用程序只需要 “请求-响应” 就够了。由于历史原因,在创建拥有双向通信机制的 web 应用程序时,就只能利用 HTTP 轮询的方式,由此产生了 “短轮询” 和 “长轮询”(注意区分短连接和长连接)。
短轮询通过客户端定期轮询来询问服务端是否有新的信息产生,缺点也是显而易见,轮询间隔大了则信息不够实时,轮询间隔过小又会消耗过多的流量,增加服务器的负担。长轮询是对短轮询的优化,需要服务端做相应的修改来支持。客户端向服务端发送请求时,如果此时服务端没有新的信息产生,并不立刻返回,而是Hang住一段时间等有新的信息或者超时再返回,客户端收到服务器的应答后继续轮询。可以看到长轮询比短轮询可以减少大量无用的请求,并且客户端接收取新消息也会实时不少。
虽然长轮询比短轮询优化了不少,但是每次请求还是都要带上HTTP请求头部,而且在长轮询的连接结束之后,服务器端积累的新消息要等到下次客户端连接时才能传递。更好的方式是只用一个TCP连接来实现客户端和服务端的双向通信,WebSocket协议正是为此而生。WebSocket是基于TCP的一个独立的协议,它与HTTP协议的唯一关系就是它的握手请求可以作为一个Upgrade request
经由HTTP服务器解析,且与HTTP使用一样的端口。WebSocket默认对普通请求使用80端口,协议为ws://
,对TLS加密请求使用443端口,协议为wss://
。
更多详细内容可以查看参考[2]。
接下来我们使用Flask-SocketIO来创建一个Socketio的Demo。具体文档可以参考:Flask-SocketIO,代码可以参考:Web Socket。
Flask==1.0.2
Flask-Login==0.4.1
Flask-Session==0.3.1
Flask_SocketIO
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
python-engineio
python-socketio
six==1.11.0
Werkzeug==0.14.1
创建app.py
:
from flask import Flask, render_template
from flask_socketio import SocketIO
async_mode = None
app = Flask(__name__)
socket_ = SocketIO(app, async_mode=async_mode)
@app.route('/')
def index():
return render_template('index.html',
sync_mode=socket_.async_mode)
if __name__ == '__main__':
socket_.run(app, debug=True)
创建前端测试页面index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket</title>
</head>
<body>
<h1>This is webSocket client</h1>
</body>
</html>
app.py
http://localhost:5000/
,成功的话会在前端页面上有提示信息:This is WebSocket Client
。具体的工程目录如下:最终的app.py
和index.html
代码如下:
from flask import Flask, render_template, session, copy_current_request_context
from flask_socketio import SocketIO, emit, disconnect
from threading import Lock
async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socket_ = SocketIO(app, async_mode=async_mode)
thread = None
thread_lock = Lock()
@app.route('/')
def index():
return render_template('index.html', async_mode=socket_.async_mode)
@socket_.on('my_event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': message['data'], 'count': session['receive_count']})
@socket_.on('my_broadcast_event', namespace='/test')
def test_broadcast_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': message['data'], 'count': session['receive_count']},
broadcast=True)
@socket_.on('disconnect_request', namespace='/test')
def disconnect_request():
@copy_current_request_context
def can_disconnect():
disconnect()
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': 'Disconnected!', 'count': session['receive_count']},
callback=can_disconnect)
if __name__ == '__main__':
socket_.run(app, debug=True)
<!DOCTYPE HTML>
<html>
<head>
<title>Socket-Test</title>
<script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
namespace = '/test';
var socket = io(namespace);
socket.on('connect', function() {
socket.emit('my_event', {data: 'connected to the SocketServer...'});
});
socket.on('my_response', function(msg, cb) {
$('#log').append('<br>' + $('<div/>').text('logs #' + msg.count + ': ' + msg.data).html());
if (cb)
cb();
});
$('form#emit').submit(function(event) {
socket.emit('my_event', {data: $('#emit_data').val()});
return false;
});
$('form#broadcast').submit(function(event) {
socket.emit('my_broadcast_event', {data: $('#broadcast_data').val()});
return false;
});
$('form#disconnect').submit(function(event) {
socket.emit('disconnect_request');
return false;
});
});
</script>
</head>
<body style="background-color:white;">
<h1 style="background-color:white;">Socket</h1>
<form id="emit" method="POST" action='#'>
<input type="text" name="emit_data" id="emit_data" placeholder="Message">
<input type="submit" value="Send Message">
</form>
<form id="broadcast" method="POST" action='#'>
<input type="text" name="broadcast_data" id="broadcast_data" placeholder="Message">
<input type="submit" value="Send Broadcast Message">
</form>
<form id="disconnect" method="POST" action="#">
<input type="submit" value="Disconnect Server">
</form>
<h2 style="background-color:white;">Logs</h2>
<div id="log" ></div>
</body>
</html>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。