python全栈开发day115、116-websocket、websocket原理、websocket加解密、简单问答机器人实现

1、websocket

	1.websocket 与轮询
轮询:
不断向服务器发起询问,服务器还不断的回复
浪费带宽,浪费前后端资源
保证数据的实时性 长轮询:
1.客户端向服务器发起消息,服务端轮询,放在另外一个地方,客户端去另外一个地方去拿
2.服务端轮询,放在另外一个地方,直接推给客户端 释放客户端资源,服务压力不可避免,节省带宽资源
数据不能实时性 websocket:是一个新的协议 Socket-io
1.前后端hold住
2.建立长链接 彻底解决实时性
解决占用带宽的问题
解决资源 2.webscoket使用
from flask import Flask, request
from geventwebsocket.websocket import WebSocket
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler app = Flask(__name__) @app.route("/ws") # WS://127.0.0.1:9527/ws
def ws():
# request.environ["wsgi.websocket"] = <链接>
user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
while 1:
msg = user_socket.receive()
print(msg)
user_socket.send(msg) if __name__ == '__main__':
http_serv = WSGIServer(("0.0.0.0", 9527), app, handler_class=WebSocketHandler)
http_serv.serve_forever()
# app.run("0.0.0.0", 9527, debug=True) 即时通讯(IM):
群聊:
from flask import Flask, request,render_template
from geventwebsocket.websocket import WebSocket
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
import json app = Flask(__name__) user_socket_dict = {} # {jinwangba:<geventwebsocket.websocket.WebSocket object at 0x000000000B35CE18>} @app.route("/")
def index():
return render_template("index.html") @app.route("/ws/<nickname>") # WS://127.0.0.1:9527/ws
def ws(nickname):
user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
if user_socket:
user_socket_dict[nickname]=user_socket
print(len(user_socket_dict))
else:
return render_template("index.html",message="请使用Websocket链接")
while 1:
msg = user_socket.receive()
for user_nick_name,socket in user_socket_dict.items(): # type:WebSocket
if user_socket != socket:
try:
socket.send(json.dumps({"sender":nickname,"msg":msg}))
except:
continue if __name__ == '__main__':
http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
http_serv.serve_forever()
# app.run("0.0.0.0", 9527, debug=True) 单聊:
from flask import Flask, request,render_template
from geventwebsocket.websocket import WebSocket
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
import json app = Flask(__name__) user_socket_dict = {} # {jinwangba:<geventwebsocket.websocket.WebSocket object at 0x000000000B35CE18>} @app.route("/")
def index():
return render_template("index.html") @app.route("/ws/<nickname>") # WS://127.0.0.1:9527/ws
def ws(nickname):
user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
if user_socket:
user_socket_dict[nickname]=user_socket
print(len(user_socket_dict),user_socket_dict)
else:
return render_template("index.html",message="请使用Websocket链接")
while 1:
msg = user_socket.receive()
msg_dict = json.loads(msg)
#{"to_user":jinwangba,msg:"DSB"}
to_user = msg_dict.get("to_user")
print("to_user:",to_user)
to_user_socket = user_socket_dict.get(to_user)
send_str = json.dumps({"sender":nickname,"msg":msg_dict.get("msg")})
to_user_socket.send(send_str) if __name__ == '__main__':
http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
http_serv.serve_forever()
# app.run("0.0.0.0", 9527, debug=True)

  

2、websocket原理
  

import socket, base64, hashlib

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1', 9527))
sock.listen(5)
# 获取客户端socket对象
conn, address = sock.accept()
# 获取客户端的【握手】信息
data = conn.recv(1024)
print(data) def get_headers(data):
header_dict = {}
header_str = data.decode("utf8")
for i in header_str.split("\r\n"):
if str(i).startswith("Sec-WebSocket-Key"):
header_dict["Sec-WebSocket-Key"] = i.split(":")[1].strip() return header_dict ws_key = get_headers(data).get("Sec-WebSocket-Key") # # magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11
magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
socket_str = ws_key + magic_string
socket_str_sha1 = hashlib.sha1(socket_str.encode("utf8")).digest()
socket_str_base64 = base64.b64encode(socket_str_sha1) response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
"Upgrade:websocket\r\n" \
"Connection: Upgrade\r\n" \
"Sec-WebSocket-Accept: %s\r\n" \
"WebSocket-Location: ws://127.0.0.1:9527\r\n\r\n" %(socket_str_base64.decode("utf8")) conn.send(response_tpl.encode("utf8"))
while 1:
msg = conn.recv(8096)
print(msg) """
b'GET / HTTP/1.1\r\n
Host: 127.0.0.1:9527\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\n
Accept-Encoding: gzip, deflate\r\n
Sec-WebSocket-Version: 13\r\n
Origin: http://localhost:63342\r\n
Sec-WebSocket-Extensions: permessage-deflate\r\n
Sec-WebSocket-Key: x/BjPHeWzOqqLxVuZq/bfw==\r\n
Cookie: session=fe2f4896-0309-4801-b8cd-9a719b26fb8d\r\n
Connection: keep-alive, Upgrade\r\n
Pragma: no-cache\r\n
Cache-Control: no-cache\r\n
Upgrade: websocket\r\n\r\n'
""" # # magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11
# magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
#
#
# def get_headers(data):
# header_dict = {}
# header_str = data.decode("utf8")
# for i in header_str.split("\r\n"):
# if str(i).startswith("Sec-WebSocket-Key"):
# header_dict["Sec-WebSocket-Key"] = i.split(":")[1].strip()
#
# return header_dict
#
#
# def get_header(data):
# """
# 将请求头格式化成字典
# :param data:
# :return:
# """
# header_dict = {}
# data = str(data, encoding='utf-8')
#
# header, body = data.split('\r\n\r\n', 1)
# header_list = header.split('\r\n')
# for i in range(0, len(header_list)):
# if i == 0:
# if len(header_list[i].split(' ')) == 3:
# header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')
# else:
# k, v = header_list[i].split(':', 1)
# header_dict[k] = v.strip()
# return header_dict
#
#
# headers = get_headers(data) # 提取请求头信息
# # 对请求头中的sec-websocket-key进行加密
# response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
# "Upgrade:websocket\r\n" \
# "Connection: Upgrade\r\n" \
# "Sec-WebSocket-Accept: %s\r\n" \
# "WebSocket-Location: ws://127.0.0.1:9527\r\n\r\n" # value = headers['Sec-WebSocket-Key'] + magic_string
# print(value)
# ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
# response_str = response_tpl % (ac.decode('utf-8'))
# # 响应【握手】信息
# conn.send(response_str.encode("utf8"))
#
# while True:
# msg = conn.recv(8096)
# print(msg)

websocket加解密

3、websocket加解密
  

上节回顾:
websocket;握手
浏览器 - 链接 - 服务器
浏览器 - 发送 - 字符串(求情头) - Sec-Websocket-Key - 服务器 服务器 - 获取Sec-Websocket-Key的值+magic_string - sha1 - base64 - 拼接一个响应头 - Sec-WebSocket-Accept值就是
服务器 - 拼接好的响应头 - 浏览器
浏览器 - Sec-WebSocket-Accept 解密得到 Sec-Websocket-Key - 握手成功与否 今日内容:
websocket 加解密
解密:
b_str = b'\x81\xfe\x01G\xa0`~dE\xe5\xf6\x81\x18\xfd\x9b\xec;\x84\xc6\xfeF\xfc\xd4\x81-\xea\x96\xe4,\x84\xc6\xc9I\xe1\xed\x81\x14\xc9\x98\xca"\x8f\xc2\xe8D\xdb\xf4\x81\x04\xc9\x9a\xdc+\x84\xc6\xedE\xe8\xf8\x8b\x1c\xec\x99\xff*\x85\xc9\xfaG\xf6\xcc\x81\x1c\xea\x91\xd8,\x86\xd3\xc0H\xcf\xe4\x81-\xd1\x98\xe4\x05\x85\xd3\xfcD\xda\xdf\x80\x19\xeb\x99\xc3+\x84\xc7\xfbC\xe0\xfc\x83$\xd6\x9a\xda-\x85\xf3\xcfD\xd9\xf5\x8c\'\xc3\x9a\xdc-\x86\xf9\xecD\xda\xf0\x81&\xe5\x91\xd8,\x85\xc1\xc4E\xdf\xe9\x80\x19\xeb\x9b\xc7\x0b\x85\xc1\xfcH\xda\xd5\x80\x1a\xee\x9b\xc06\x88\xfe\xe1O\xdc\xf2\x83;\xf6\x96\xdb\x1d\x85\xfb\xecE\xd8\xe3\x80\x19\xeb\x98\xca*\x89\xff\xe3O\xdc\xf2\x82\x0c\xd2\x98\xee\x05\x84\xc7\xefD\xda\xf0\x8d9\xfb\x9a\xdc+\x84\xc7\xfbC\xe0\xfc\x8c\x0f\xfa\x9b\xca<\x85\xc2\xe4E\xdc\xde\x81<\xc3\x9b\xf4\x0c\x8f\xc2\xe8D\xdb\xdb\x81%\xe9\x9b\xe1(\x85\xc6\xf9I\xe1\xe9\x81\x1e\xd7\x91\xd8,\x86\xff\xc6E\xdc\xe6\x81\x1f\xf7\x9b\xc7\x0b\x84\xc7\xefF\xd0\xea\x8b\x1c\xec\x9a\xdc-\x85\xd0\xf8E\xc6\xfa\x8c\'\xca\x96\xeb\x12\x88\xe8\xe0O\xdc\xf2\x81\x1c\xf5\x9b\xf2\x1b\x85\xda\xd5D\xd9\xf7\x8b\x1c\xec\x9a\xdf\x05\x85\xdf\xfaE\xdf\xde\x8c\x10\xef\x9a\xdd+\x88\xc9\xcbD\xd9\xe1'
c_str = b'\x81\xfe\x02d\xbe@<\x07'
# 123 \x81
#[\x81,\x83,\xc8,\xbd,\xa6,\x9c,\xf9,\x8f,\x95]
#
#
#
#--------
#
# 0111111 127
# 0111110 126 data_lenth = b_str[1] & 127
# print(data_lenth) # data_lenth == 127 之后的多少位为数据长度3-10字节代表数据长度 11-14为mask_key
if data_lenth == 127:
extend_payload_len = b_str[2:10]
mask = b_str[10:14]
data = b_str[14:] # data_lenth == 126 之后的多少位为数据长度3-4字节代表数据长度 65535 5-8为mask_key
if data_lenth == 126:
extend_payload_len = b_str[2:4]
mask = b_str[4:8]
data = b_str[8:] # data_lenth <= 125 当前的 data_lenth 就是数据的长度 125 3-6为mask_key
if data_lenth <= 125:
extend_payload_len = b_str[1]
mask = b_str[2:6]
data = b_str[6:] str_byte = bytearray() for i in range(len(data)):
byte = data[i] ^ mask[i % 4] #
str_byte.append(byte) print(str_byte.decode("utf8"))# 加密:
import struct
msg_bytes = "先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也".encode("utf8")
token = b"\x81"
length = len(msg_bytes) if length < 126:
token += struct.pack("B", length)
elif length == 126:
token += struct.pack("!BH", 126, length)
else:
token += struct.pack("!BQ", 127, length) msg = token + msg_bytes print(msg)

websocket握手和加解密

4、人工智能简易机器人
  

1.百度ai
2.基于百度ai实现了语音合成
3.基于百度ai实现了语音识别

from aip import AipSpeech
import os
from uuid import uuid4
from wav2pcm import wav_to_pcm APP_ID = ''
API_KEY = 'zdU6ldOh7CeQvFFzw9GWhwZr'
SECRET_KEY = 'h5eVzR2G4EPFf78uzceC1zHL6Qj88RCY' client = AipSpeech(APP_ID, API_KEY, SECRET_KEY) # client.setConnectionTimeoutInMillis(5000) # 建立连接的超时时间(单位:毫秒)
# client.setSocketTimeoutInMillis(10000) # 通过打开的连接传输数据的超时时间(单位:毫秒)
# 语音合成
def new_synthesis(text):
result = client.synthesis(text, 'zh', 1, {
'vol': 5, # 音量,取值0-15,默认为5中音量
'spd': 5, # 语速,取值0-9,默认为5中语速
'pit': 5, # 音调,取值0-9,默认为5中语调
'per': 4 # 发音人选择, 0为女声,1为男声,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女
})
audio_file_path = str(uuid4()) + ".mp3"
# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
with open(audio_file_path, 'wb') as f:
f.write(result)
return audio_file_path # 读取文件
def get_file_content(pcm_file_path):
with open(pcm_file_path, 'rb') as fp:
return fp.read() # 语音识别
def new_asr(filePath):
# 将录音机文件wma转换成pcm
pcm_file_path = wav_to_pcm(filePath) # 识别本地文件
res = client.asr(get_file_content(pcm_file_path), 'pcm', 16000, {
'dev_pid': 1536,
})
try:
text = res.get('result')[0]
except Exception as e:
text = "对不起,没有听清你说的啥,请再说一遍。"
os.remove(pcm_file_path)
return text if __name__ == '__main__':
new_asr('audio.wma')

语音合成和语音识别

FFmpeg 转换PCM音频格式

# wav2pcm.py 文件内容
import os def wav_to_pcm(wav_file):
# 假设 wav_file = "音频文件.wav"
# wav_file.split(".") 得到["音频文件","wav"] 拿出第一个结果"音频文件" 与 ".pcm" 拼接 等到结果 "音频文件.pcm"
pcm_file = "%s.pcm" % (wav_file.split(".")[0]) # 就是此前我们在cmd窗口中输入命令,这里面就是在让Python帮我们在cmd中执行命令
os.system("ffmpeg -y -i %s -acodec pcm_s16le -f s16le -ac 1 -ar 16000 %s" % (wav_file, pcm_file))
os.remove(wav_file)
return pcm_file

wav2pcm.py

4.基于百度ai NLP技术中的Simnet 实现 短文本相似度

# 基于百度ai的Simnet的 实现短文本相似度
from aip import AipNlp APP_ID = ''
API_KEY = 'zdU6ldOh7CeQvFFzw9GWhwZr'
SECRET_KEY = 'h5eVzR2G4EPFf78uzceC1zHL6Qj88RCY' client = AipNlp(APP_ID, API_KEY, SECRET_KEY) def new_simnet(text1, text2):
ret = client.simnet(text1, text2)
return ret.get('score')

基于百度ai的Simnet的 实现短文本相似度

5.简单问答 + Tuling机器人
  

import requests

def tuling_answer(text):
to_tuling_url = "http://openapi.tuling123.com/openapi/api/v2" # 接口地址
json_data = {
"reqType": 0,
"perception": {
"inputText": {
"text": text
},
},
"userInfo": {
"apiKey": "93e5736f3b9e496bbb63a0f29afa4d4d",
"userId": "test123"
}
}
res = requests.post(to_tuling_url, json=json_data).json()
answer = res.get("results")[0]['values']['text']
return answer if __name__ == '__main__': tuling_answer('北京天气')

tuling_answer

6.web录音知道里面是干什么的,Audio标签 src音频地址 autoplay当src加载完成时自动播放 controls 显示或关闭播放器

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> </head>
<body>
<audio src="" autoplay controls id="player"></audio> <button onclick="start_reco()">录制消息</button>
<br>
<button onclick="stop_reco()">发送语音消息</button> </body>
<script src="/static/Recorder.js"></script>
<script type="application/javascript">
var serv = "http://127.0.0.1:9527";
var ws_serv = "ws://127.0.0.1:9528/ws"; var get_music = serv + "/get_audio/";
var ws = new WebSocket(ws_serv);
ws.onmessage = function (data) {
console.log(data.data,111111111)
document.getElementById("player").src = get_music + data.data
};
var reco = null;
var audio_context = new AudioContext();
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia); navigator.getUserMedia({audio: true}, create_stream, function (err) {
console.log(err)
}); function create_stream(user_media) {
var stream_input = audio_context.createMediaStreamSource(user_media);
reco = new Recorder(stream_input);
} function start_reco() {
reco.record();
} function stop_reco() {
reco.stop();
get_audio();
reco.clear();
} function get_audio() {
reco.exportWAV(function (wav_file) {
ws.send(wav_file);
})
} </script>
</html>

html

7.基于websocket传输语音
8.return send_file(file_name)
  

from flask import Flask, send_file, render_template
from queue import Queue
import os
q = Queue() # type:Queue app = Flask(__name__) # type:Flask @app.route("/index")
def index():
return render_template("index1.html") temp_file_name = [] @app.route('/get_audio/<filename>')
def get_audio(filename):
# 利用队列存储临时生成的文件名,下一次请求来的时候删除文件
if not q.empty():
temp = q.get()
print(temp)
os.remove(temp)
q.put(filename)
return send_file(filename) if __name__ == '__main__':
app.run(host='0.0.0.0', port=9527)

flask_app.py

from flask import Flask, request
from geventwebsocket.websocket import WebSocket
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
from uuid import uuid4 from baidu_asr_and_synthesis import new_asr, new_synthesis
from simple_questions_answers import question_answer app = Flask(__name__) # type:Flask @app.route('/ws')
def ws():
user_websocket = request.environ.get('wsgi.websocket') # type:WebSocket
if user_websocket:
while 1:
res = user_websocket.receive()
# 保存接收音频文件
rev_file_name = ("%s" + ".wav") % str(uuid4())
with open(rev_file_name, 'wb') as f:
f.write(res)
print(rev_file_name)
# 将接收的音频文件转换为文本
audio_to_text = new_asr(rev_file_name)
print('audio_to_text',audio_to_text)
# 根据问题文本回答问题
answer_text = question_answer(audio_to_text)
print('answer_text',answer_text)
# 将问题答案转成音频文件
answer_audio_file_path = new_synthesis(answer_text)
print('answer_audio_file_path',answer_audio_file_path)
# 将音频文件路径发给前端
user_websocket.send(answer_audio_file_path) if __name__ == '__main__':
http_serv = WSGIServer(('0.0.0.0', 9528), app, handler_class=WebSocketHandler)
http_serv.serve_forever()

flask_ws.py

上一篇:Spring实战 (第3版)——AOP


下一篇:C++输入输出流的重载