专栏首页搜狗测试语音评测之——websocket

语音评测之——websocket

前言

前段时间小编收到一份测试任务要求对搜狗输入法的语音功能进行评测。评测任务主要拆分为评测语料的选取和整理,硬件的调研和采购,评测工具的开发以及评测的执行和结果整理。小编负责评测工具服务端的开发工作,主要使用了websocket的技术,此次与大家做一个简单的分享。

评测过程

语音的评测过程中由web端连接音响实现语音的播放功能,手机客户端接收语音并处理。这整个过程中web端和客户端的正确通信是保证整个过程顺畅高效的重要环节。

评测过程会逐条播放音频,每一条音频播放后web端需要知道每个手机客户端的状态(是否语音处理完毕,是否准备好接收下一条语音等等),以此来决定何时开始播放下一条音频;同理客户端也需要实时接收到web端的播放状态(何时开始,何时结束等等)。整个评测过程中web端和客户端需要频繁通信,所以我们需要选择一个合适的通讯技术以保证效率和质量。

通讯技术

在选择通信技术之前我们先了解几个基本概念:

短连接:每次http请求都会建立tcp连接,管理很容易,但是我们知道一次完整的tcp连接包含3次握手和4次挥手,如果频繁请求,将在tcp的建立和关闭操作上浪费较多时间和带宽。

长连接:http1.1之后默认建立长连接,由客户端发出请求,服务端接收请求,双方建立连接,在服务端没有返回之前保持连接,当客户端在发送请求时,它会使用同一个连接。这一直继续到客户端或者服务端认为会话已经结束,其中一方中断连接,更适用于追求实时性高的场景比如数据库的连接等等。

在本次评测过程中由于客户端与服务端通信频繁,且对实时性要求较高,开始便考虑使用长连接的方式。但是http协议一般只能由客户端发起,服务端无法直接进行推送,这就导致了如果服务端有持续的变化客户端想要获知就比较麻烦。而我们的评测过程中客户端会实时发送自己的状态信息给服务端,而服务端也会主要发送信息给客户端告知自己当前的状态,而这种真的全双工的协议便是websocket协议。

websocket:全双工通信协议,在第一次tcp链路建立之后,后续数据客户端和服务端都可以主动发送,不需要发送请求头,并且这个连接会持续存在直到客户端或者服务器端的某一方主动关闭连接,与HTTP长连接不同,WebSocket可以更灵活的控制连接关闭的时机,而不是HTTP协议的Keep-Alive一到,服务端立马就关闭。

websocket实现

websocket使用了自定义的协议,未加密的连接不再是http://,而是ws://,默认端口为80,加密的连接也不是https://,而是wss://,默认端口为443。比如:

ws://example.com/wsapi
wss://wsapi.example.com/

一个典型的Websocket握手请求如下:

客户端请求

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

服务器回应

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/
  • Connection 必须设置 Upgrade,表示客户端希望连接升级。
  • Upgrade 字段必须设置 Websocket,表示希望升级到 Websocket 协议。
  • Sec-WebSocket-Key 是随机的字符串,服务器端会用这些数据来构造出一个 SHA-1 的信息摘要。把 “Sec-WebSocket-Key” 加上一个特殊字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算 SHA-1 摘要,之后进行 BASE-64 编码,将结果做为 “Sec-WebSocket-Accept” 头的值,返回给客户端。如此操作,可以尽量避免普通 HTTP 请求被误认为 Websocket 协议。

websocket 协议本质上是一个基于 TCP 的协议。对于如何实现一个基本的websocket通信也非常容易,可以用任意的编程语言来实现,只要该语言能实现基本的Berkeley sockets。本次评测中小编使用python作为web端开发语言,而且python中对于websocket的实现封装了很多适用的库可以直接调用,为开发过程大大降低了难度。

客户端

websocket 使用 ws 或 wss 的统一资源标志符。而js就支持ws协议,因此使用websocket的时候,前端的使用一般都比较规范。

var s = new WebSocket("ws://%s/<id>");//创建一个websocket连接
s.onopen = function() {}
s.onmessage = function(e) {}//监听消息
s.onerror = function(e) {}//监听错误
s.onclose = function(e) {}//关闭连接
s.send(value);//发送消息

服务端

python中常用的通信框架为flask,该框架中以gevent-websocket库为例,以下为服务端部分实现代码,代码简单实现了服务端接收到客户端发送的消息(message = wsock.receive())并将消息同样发送给客户端(wsock.send(message)):

from flask import Flask
from gevent-websocket import WebSocketError
from gevent.pywsgi import WSGIServer
from gevent-websocket.handler import WebSocketHandler
 
app = Flask(__name__)
users = dict()
@app.route('/websocket/<uid>')
def handle_websocket(id):
    wsock = request.environ.get('wsgi.websocket')
    users[id] = wsock
 
    if not wsock:
        abort(400, 'Expected WebSocket request.')
 
    while True:
        try:
            message = wsock.receive() # 接收客户端发来的信息
        except WebSocketError:
            break
 
        if message:
            for uid in users:
                try:
                    users[uid].send(message) # 给客户端推送信息
                except WebSocketError:
                    print u'用户已断开连接'
 
    # 如果有客户端断开,则删除这个断开的websocket
    users.pop(id)
 
if __name__ == '__main__':
    server = WSGIServer(("0.0.0.0", 8000), app, handler_class=WebSocketHandler)
    server.serve_forever()

本文分享自微信公众号 - 搜狗测试(SogouQA),作者:ly

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 接口测试之文件重定向法

    部署方法: 第一步:部署一台测试服务器,找一款可以访问服务器的软件,例如:WinSCP; 第二步:前端预先将客户端返回的数据格式以及数据字段保存在本地,例如:...

    用户5521279
  • 【TestNG快速上手】一、接口自动化

    TestNG是基于java语言并集成JUnit和NUnit的测试框架,具有如下特性:

    用户5521279
  • 你不得不知道的流程规范@用户反馈跟进流程

    项目终于上线了,大家终于松了一口气o(* ̄︶ ̄*)o,但是接踵而来的可能是来自四面八方的用户反馈信息,有问题有建议...... 作为专业的测试人员,我们又忙着...

    用户5521279
  • Java后端WebSocket的Tomcat实现

    文章摘要随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与...

    庞小明
  • Python枚举类

    更好的办法是为这样的枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例。Python提供了Enum来来实现这个功能:

    小破孩的梦想空间
  • python 面向对象技巧 枚举类

    更好的方法是为这样的枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例。Python提供了Enum类来实现这个功能:

    葫芦
  • Python爬虫:selenium的填坑心得

    在之前的文章中说过,模拟浏览器在现在的python库中有两个选择Mechanize与Selenium:然而Mechanize不支持JavaScript,Sele...

    企鹅号小编
  • 11-散列3 QQ帐户的申请与登陆 (25分)

    实现QQ新帐户申请和老帐户登陆的简化版功能。最大挑战是:据说现在的QQ号码已经有10位数了。

    AI那点小事
  • 让容器的世界变得更美好

    容器技术发展迅猛,近期热点活动不断,作为容器世界的主力军,VMware也在这些活动中频繁亮相,着实吸引了不少眼球。

    Henry Zhang
  • 圆点

    题目背景 中考了,Pg看着数学卷子的压轴题,陷入了沉思…… 题目描述 众所周知,平面中的每一个整点都有且仅有一个圆心在原点的圆穿过,我们定义这个整点的权值...

    glm233

扫码关注云+社区

领取腾讯云代金券