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

python全栈开发day115、116-websocket、websocket原理、websocket加解密、简单问答机器人实现的更多相关文章

  1. Python全栈开发【面向对象进阶】

    Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...

  2. Python全栈开发【面向对象】

    Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...

  3. Python全栈开发【模块】

    Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...

  4. Python全栈开发【基础四】

    Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...

  5. Python全栈开发【基础三】

    Python全栈开发[基础三]  本节内容: 函数(全局与局部变量) 递归 内置函数 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 def 函数名(参数): ... 函数体 . ...

  6. Python全栈开发【基础二】

    Python全栈开发[基础二] 本节内容: Python 运算符(算术运算.比较运算.赋值运算.逻辑运算.成员运算) 基本数据类型(数字.布尔值.字符串.列表.元组.字典) 其他(编码,range,f ...

  7. Python全栈开发【基础一】

    Python全栈开发[第一篇] 本节内容: Python 的种类 Python 的环境 Python 入门(解释器.编码.变量.input输入.if流程控制与缩进.while循环) if流程控制与wh ...

  8. python 全栈开发之路 day1

    python 全栈开发之路 day1   本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...

  9. Python全栈开发

    Python全栈开发 一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了. 一.装饰器 装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为“ ...

随机推荐

  1. mybatis 插入 含有美元符号($) 字符串 报 java.lang.IndexOutOfBoundsException: No group 2 的问题

    一:问题描述: 在springboot-security框架生成BCryptPasswordEncoder()方法生成加密后的密码后,带有$符号,导致新增用户的时候插入不了,报(IndexOutOfB ...

  2. python之路day12--装饰器的进阶

    装饰器# 开发原则:开发封闭原则# 装饰器的作用:在不改变原函数的调用函数下,在函数的前后添加功能.# 装饰器的本质:闭包函数 import time def timmer(f): #func #ti ...

  3. re模块正则表达式

    regular expression / regex / RE 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配.Python 自1.5版本起增加了re 模块,它提供 ...

  4. Helm包管理工具(简介、安装、方法)

    认识Helm 每次我们要部署一个应用都需要写一个配置清单(维护一套yaml文件),但是每个环境又不一样.部署一套新的环境成本是真的很高.如果我们能够使用类似于yum的工具来安装我们的应用的话那就太好了 ...

  5. SpringMVC运行流程

    Spring工作流程描述       1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获:       2. DispatcherServl ...

  6. [Android] Android 手机下 仿 今日头条 新闻客户端

    利用一个月的时间,自学了 Android 开发 ,为了检验学习成果,特意 开发了这个  仿 今日头条 新闻客户端 AppNews 包括图文新闻+视频新闻+图片新闻 预览演示如下: 功能说明: 1)底部 ...

  7. 三步法搞定CTF中的SQL注入题型

    三步法: 一.找到注入点 二.Fuzz出未过滤字符 三.构造payload/写脚本 例题1 打开题目: 第一步,寻找注入点. 输入用户名123456,密码123456,返回结果username err ...

  8. YOLO学习

    YOLO1:https://blog.csdn.net/m0_37192554/article/details/81092514 https://blog.csdn.net/shuiyixin/art ...

  9. Lambda表达式与函数式接口

    Lambda表达式的类型,也被称为目标类型(targer type),Lambda表达式的目标类型必须是"函数式接口(functional interface)".函数式接口代表只 ...

  10. makefile 嵌套

    目录结构: dynamic 和 static 两个目录实现加法功能, 分别生成动态库和静态库,   main.c 主文件链接加法功能,  终端命令执行:   make dynamic=1  则编译动态 ...