最近在做一个类似直播平台的网络应用,想要使前端能不断的从服务器获取视频流。
首先我们要选择一种服务器与浏览器连接方式。目前主要有短链接与全连接两种。
其中短连接又分为传统轮询与长轮询。
轮询(属于短链接):客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。
优点:后端程序编写比较容易。
缺点:请求中有大半是无用,浪费带宽和服务器资源。
实例:适于小型应用。
长轮询(属于短连接,属于comet技术):客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。 与短轮询相比其实就是增加了超时时间而已。示意图如下
web客户端代码如下:
//向后台长轮询消息
function longPolling(){
$.ajax({
async : true,//异步
url : 'longPollingAction!getMessages.action',
type : 'post',
dataType : 'json',
data :{},
timeout : 30000,//超时时间设定30秒
error : function(xhr, textStatus, thrownError) {
longPolling();//发生异常错误后再次发起请求
},
success : function(response) {
message = response.data.message;
if(message!="timeout"){
broadcast();//收到消息后发布消息
}
longPolling();
}
});
}
优点:在无消息的情况下不会频繁的请求,耗费资源小。
缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。
实例:WebQQ、Hi网页版、Facebook IM。
长连接:http1.1协议都是默认使用长连接,即浏览器与服务器一直保持连接,即使没有数据要传递。它主要适用于需要频繁发送数据的情景,这样就能减少连接开销。
优点:消息即时到达,不发无用请求;管理起来也相对方便。
缺点:服务器维护一个长连接会增加开销。
实例:Gmail聊天
长连接主要有两大类,一种是服务器单向给客户端推送消息的单工通信,还有两者可以互相发送数据的websocket通信。
单工通信针对字节流的主要技术有基于ajax的字节流实时推送,基于SSE(Server-Event Events)两种方式。在javascript高级程序设计有较为详细的解释。如果是图片需要服务器推送刷新直接指定图片的src为服务器推送网址即可。本次工程的图像刷新就属于单工通信。刷新图片主要是要注意服务器端要指定http协议的报文头部的mineType和Content-Type字段。建议看图解http协议这本书来了解协议细节。
服务器端核心代码如下:
def gen(camera, start=False):
"""Video streaming generator function."""
while start:
frame = camera.get_frame()
#字符串前面加b表示 后面字符串是bytes 类型。
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/cv_camera')
def cv_camera_feed():
print("**begin**")
camera = Camera_cv()
#通常一个HTTP响应只能包含一个数据块。但MIME有一种机制可用一个报文(或HTTP响应)表示将多个数据块,
# 这种机制就是成为“multipart/mixed”的标准MIME类型。
#这其实是一种基于服务器推送的在浏览器异步刷新的方法
#“replace”表示每一个新数据块都会代替前一个数据块。也就是说,新数据不是附加到旧数据之后,而是替代它。
return Response(
gen(camera, True), mimetype='multipart/x-mixed-replace; boundary=frame')
其中camera.get_frame()函数的最后一句是这样。
yield cv2.imencode('.jpg', frame)[1].tobytes()
"""简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,
Python 解释器会将其视为一个 generator,调用 frames()不会执行frames()函数,而是返回一个 iterable 对象!
在 for 循环执行时,每次循环都会执行 frames() 函数内部的代码,执行到 yield 语句时,fab 函数就返回一个迭代值"""
Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。
优点:实现真正的即时通信,而不是伪即时。
缺点:客户端必须安装Flash插件;非HTTP协议,无法自动穿越防火墙。
实例:网络互动游戏。
参考链接
基于HTTP的长轮询简单实现
https://www.e-learn.cn/content/jquery/1155365
https://www.cnblogs.com/leaven/p/3514650.html