本节目录:

(一)笔记总结;

(二)gevent-websocket+flask+javascript实现WS即时通信

  (1)无昵称群聊

  (2)有昵称群聊

  (3)私聊

三种通信模型简述: 

(1)轮询:
客户端周期性不间断高频率的给服务器发送请求:
客户端请求--服务器响应--断开连接,请求次数QPS比较频繁,对客户端和服务器的配置要求比较高
(2)长轮询:
客户端周期性不间断的给服务器发送请求:
客户端与服务器建立的连接会保持一定时间,因此请求相对不会特别频繁
(3)长连接:
客户端与服务端建立连接后,如果不是特殊原因(客户端主动断开,服务器故障)连接会一直保持
同时通过多线程进行IO多路复用技术解决并发问题

flask中基于gevent-websocket的IO多路复用技术进行长连接通信:  

(1)基于gevent-websocket的IO多路复用长连接通信,需要导入一下模块:
#pip install gevent-websocket导入IO多路复用模块
from geventwebsocket.handler import WebSocketHandler #提供WS(websocket)协议处理
from geventwebsocket.server import WSGIServer #websocket服务承载
#WSGIServer导入的就是gevent.pywsgi中的类
# from gevent.pywsgi import WSGIServer
from geventwebsocket.websocket import WebSocket #websocket语法提示
(2)路由视图函数中的处理必须通过request.environ.get('wsgi.websocket')获取与客户端的ws连接client_socket:
 #websocket协议通信如下(http请求正常处理即可)
@app.route()
def func():
client_socket=request.environ.get('wsgi.websocket')
while 1:
client_socket.recive()
...
client_socket.send(str)
...
(3)flask项目启动如下:
WSGIServer默认处理的是http请求,路由视图中可以正常使用http,
但是在使用ws协议时务必在视图函数通过request.environ.get('wsgi.websocket')获取与客户端的ws连接client_socket,
通过连接client_socket进行client_socket.recive()/client_socket.send()通信,这连个方法会对字符串自动进行编解码)
http_server=WSGIServer(('192.168.16.14',8888),application=app,handler_class=WebSocketHandler。
http_server.serve_forever()
(4)前端页面使用js进行WS(websocket)请求:
浏览器提供了websocket客户端,直接new创建websocket连接ws,
(ws状态码0表示已创建未连接,1表示已连接保持中,2表示客户端主动断开连接,3表示服务端断开连接),
通过ws.onmessage=function (MessageEvent){}监听执行回调函数获取信息MessageEvent.data,
通过ws.send()发送信息。
<script>
var ws = new WebSocket('ws://192.168.16.14:8888/websocket');
ws.onmessage = function (MessageEvent) {
console.log(MessageEvent);
console.log(MessageEvent.data);
}; function send() {
var msg = document.getElementById('msg').value;
ws.send(msg);
}
</script>

http请求协议和websocket请求协议的请求原数据request.environ和请求头部信息request.headers比较:
http-environ:

{
'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'gevent/1.4 Python/3.6',
'SCRIPT_NAME': '', 'wsgi.version': (1, 0),
'wsgi.multithread': False, 'wsgi.multiprocess': False,
'wsgi.run_once': False, 'wsgi.url_scheme': 'http',
'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>,
'SERVER_NAME': 'PC-Yang', 'SERVER_PORT': '', 'REQUEST_METHOD': 'GET',
'PATH_INFO': '/websocket', 'QUERY_STRING': '', 'SERVER_PROTOCOL': 'HTTP/1.1',
'REMOTE_ADDR': '192.168.16.14', 'REMOTE_PORT': '', 'HTTP_HOST': '192.168.16.14:8888',
'HTTP_CONNECTION': 'keep-alive', 'HTTP_PRAGMA': 'no-cache', 'HTTP_CACHE_CONTROL': 'no-cache',
'HTTP_UPGRADE_INSECURE_REQUESTS': '',
'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9',
'wsgi.input': <gevent.pywsgi.Input object at 0x03A9DC00>,
'wsgi.input_terminated': True, 'werkzeug.request': <Request 'http://192.168.16.14:8888/websocket' [GET]>
}

http-environ

http-headers:

'''
Host: 192.168.16.14:8888
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
'''

http-headers

websocket-environ: 'wsgi.websocket': <geventwebsocket.websocket.WebSocket object at 0x03A9DC00>,websocket连接

'''
{
'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'gevent/1.4 Python/3.6',
'SCRIPT_NAME': '', 'wsgi.version': (1, 0), 'wsgi.multithread': False,
'wsgi.multiprocess': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http',
'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>,
'SERVER_NAME': 'PC-Yang', 'SERVER_PORT': '8888', 'REQUEST_METHOD': 'GET',
'PATH_INFO': '/websocket', 'QUERY_STRING': '', 'SERVER_PROTOCOL': 'HTTP/1.1',
'REMOTE_ADDR': '192.168.16.14', 'REMOTE_PORT': '61591', 'HTTP_HOST': '192.168.16.14:8888',
'HTTP_CONNECTION': 'Upgrade', 'HTTP_PRAGMA': 'no-cache', 'HTTP_CACHE_CONTROL': 'no-cache',
'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
'HTTP_UPGRADE': 'websocket', 'HTTP_ORIGIN': 'http://192.168.16.14:8888', 'HTTP_SEC_WEBSOCKET_VERSION': '13',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9',
'HTTP_SEC_WEBSOCKET_KEY': 'Oyfq0MCEBnsypKstjjRvYg==',
'HTTP_SEC_WEBSOCKET_EXTENSIONS': 'permessage-deflate; client_max_window_bits',
'wsgi.input': <gevent.pywsgi.Input object at 0x03A9DCA8>,
'wsgi.input_terminated': True, 'wsgi.websocket_version': '13', 'wsgi.websocket': <geventwebsocket.websocket.WebSocket object at 0x03A9DC00>, 'werkzeug.request': <Request 'http://192.168.16.14:8888/websocket' [GET]>
}
'''

websocket-environ

websocket-headers:     Upgrade: websocket   #websocket请求中的标识

'''
Host: 192.168.16.14:8888
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Upgrade: websocket #websocket请求中的标识 Origin: http://192.168.16.14:8888
Sec-Websocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Sec-Websocket-Key: Oyfq0MCEBnsypKstjjRvYg==
Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits
'''

websocket-headers

(1)基于websocket+flask实现的群聊无昵称即时通信

  flask_websocket(MUC_Nonick).py  

 '''
基于websocket+flask实现的群聊无昵称即时通信
设计列表client_list = []来存储客户端与服务器的连接,
服务收到任意客户端的信息(信息时),对连接存储列表进行遍历获取每个连接,直接进行转发
'''
from flask import Flask, render_template, request # pip install gevent-websocket导入IO多路复用模块
from geventwebsocket.handler import WebSocketHandler # 提供WS(websocket)协议处理
from geventwebsocket.server import WSGIServer # websocket服务承载
# WSGIServer导入的就是gevent.pywsgi中的类
# from gevent.pywsgi import WSGIServer
from geventwebsocket.websocket import WebSocket # websocket语法提示 app = Flask(__name__) # @app.route('/websocket')
# 多个客户端可以同时给falsk服务端发送ws协议的信息
# def websocket():
# client_socket=request.environ.get('wsgi.websocket') #type:WebSocket
# while 1:
# msg_from_cli=client_socket.receive()
# print(msg_from_cli)
# 多个客户端可以同时给falsk服务端发送ws协议的信息,同时服务端将信息转送到每个客户端页面,实现多人聊天室即时通信
client_list = [] @app.route('/websocket')
def websocket():
client_socket = request.environ.get('wsgi.websocket') # type:WebSocket
client_list.append(client_socket)
# print(len(client_list), client_list)
while 1:
msg_from_cli = client_socket.receive()
# print(msg_from_cli)
#收到任何一个客户端的信息都进行全部转发(注意如果某个客户端连接断开,在遍历发送时连接不存在会报错,需要异常处理)
for client in client_list:
try:
client.send(msg_from_cli)
except Exception as e:
continue @app.route('/chat')
def chat():
return render_template('MUC_Nonick.html') if __name__ == '__main__':
# app.run('192.168.16.14',8888,debug=True)
http_server = WSGIServer(('192.168.16.14', 8888), application=app, handler_class=WebSocketHandler)
http_server.serve_forever()

flask_websocket(MUC_Nonick).py

  MUC_Nonick.html  

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多用户聊天无昵称</title>
</head>
<body>
<div id="chat_room">
<p>请输入聊天内容:<input type="text" id="msg">
<button id="send" onclick="send()">发送</button>
</p>
<div id="chat_content"></div>
</div>
</body>
<script type="application/javascript">
var ws = new WebSocket('ws://192.168.16.14:8888/websocket');
ws.onmessage = function (MessageEvent) {
//console.log(MessageEvent);
//console.log(MessageEvent.data);
var time=new Date();
var t= time.toLocaleString();
var p=document.createElement("p");
p.innerText="("+t+")"+MessageEvent.data;
document.getElementById('chat_content').appendChild(p);
}; function send() {
var msg = document.getElementById('msg').value;
ws.send(msg);
}
</script>
</html>

MUC_Nonick.html

(2)基于websocket+flask实现的群聊有昵称即时通信

  版本一:通过动态路有参数获取客户端昵称:

  flask_websocket(MUC_nick_route).py  

 '''
基于websocket+flask实现的群聊即时通信
设计字典client_dict = {}来存储{客户端的名字:客户端与服务器的连接},客户端的名字通过动态路由参数获取到,
服务器接收客户端发来的信息(经过json序列化后的字典),对存储连接信息的字典进行遍历,获取客户端的连接,直接转发
'''
from flask import Flask, render_template, request
from geventwebsocket.handler import WebSocketHandler # 提供WS(websocket)协议处理
from geventwebsocket.server import WSGIServer # websocket服务承载
from geventwebsocket.websocket import WebSocket # websocket语法提示 app = Flask(__name__) client_dict = {} @app.route('/websocket/<client_name>')#通过动态路由参数获取昵称,必须在视图函定义同名形参接收
def websocket(client_name):
client_socket = request.environ.get('wsgi.websocket') # type:WebSocket
client_dict[client_name] = client_socket
# print(len(client_dict), client_dict)
while 1:
msg_from_cli = client_socket.receive()
for client in client_dict.values():
try:
client.send(msg_from_cli)
except Exception as e:
continue @app.route('/chat')
def chat():
return render_template('MUC_nick_route.html') if __name__ == '__main__':
# app.run('192.168.16.14',8888,debug=True)
http_server = WSGIServer(('192.168.16.14', 8888), application=app, handler_class=WebSocketHandler)
http_server.serve_forever()

flask_websocket(MUC_nick_route).py

  MUC_nick_route.html

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多用户聊天无昵称</title>
</head>
<body>
<div id="chat_room">
<p>输入昵称进入多人聊天室:<input type="text" id="client_name"></input>
<button id='login' onclick="login()">登录</button>
</p>
<p id='chat_msg' hidden="hidden">请输入聊天内容:<input type="text" id="msg">
<button id="send" onclick="send()">发送</button>
</p>
<div id="chat_content" hidden="hidden"></div>
</div>
</body>
<script type="application/javascript">
var ws = null;
var name=null; function login() {
document.getElementById('login').setAttribute('hidden', 'hidden');
document.getElementById('client_name').setAttribute('disabled', 'disabled');
document.getElementById('chat_msg').removeAttribute('hidden');
document.getElementById('chat_content').removeAttribute('hidden');
name = document.getElementById('client_name').value;
//进行WS实例化
ws = new WebSocket('ws://192.168.16.14:8888/websocket/' + name); //监听服务器发来的消息(json数据)
ws.onmessage = function (MessageEvent) {
//console.log(MessageEvent);
//console.log(MessageEvent.data);
var content_str = JSON.parse(MessageEvent.data);
var time = new Date();
var t = time.toLocaleTimeString();
var p = document.createElement("p");
p.innerText = content_str.name + "(" + t + "):" + content_str.msg;
document.getElementById('chat_content').appendChild(p);
};
}; //聊天信息发送(json数据)
function send() {
var msg = document.getElementById('msg').value;
var data = {
name: name,
msg: msg,
};
var data_json = JSON.stringify(data);
ws.send(data_json);
}
</script>
</html>

MUC_nick_route.html

 

  版本二:通过websocket接收客户端发来基于websocket发来的昵称: 

  flask_websocket(MUC_nick).py

 '''
基于websocket+flask实现的群聊即时通信
设计字典client_dict = {}来存储{客户端的名字:客户端与服务器的连接},客户端的名字通过客户端执行WS请求协议发送获取,
服务器再持续接收客户端发来的信息(经过json序列化后的字典),对存储连接信息的字典进行遍历,获取客户端的连接,直接转发
'''
from flask import Flask, render_template, request
from geventwebsocket.handler import WebSocketHandler # 提供WS(websocket)协议处理
from geventwebsocket.server import WSGIServer # websocket服务承载
from geventwebsocket.websocket import WebSocket # websocket语法提示 app = Flask(__name__) client_dict = {} @app.route('/websocket')
def websocket():
client_socket = request.environ.get('wsgi.websocket') # type:WebSocket
# print(client_socket)
client_name = client_socket.receive()
client_dict[client_name] = client_socket
# print(len(client_dict), client_dict)
while 1:
msg_from_cli = client_socket.receive()
# msg_from_cli_str=json.loads(msg_from_cli)
# print(msg_from_cli_str)
for client in client_dict.values():
try:
client.send(msg_from_cli)
except Exception as e:
continue @app.route('/chat')
def chat():
return render_template('MUC_nick.html') if __name__ == '__main__':
# app.run('192.168.16.14',8888,debug=True)
http_server = WSGIServer(('192.168.16.14', 8888), application=app, handler_class=WebSocketHandler)
http_server.serve_forever()

flask_websocket(MUC_nick).py

  MUC_nick.html  

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多用户聊天无昵称</title>
</head>
<body>
<div id="chat_room">
<p>输入昵称进入多人聊天室:<input type="text" id="client_name"></input>
<button id='login' onclick="login()">登录</button>
</p>
<p id='chat_msg' hidden="hidden">请输入聊天内容:<input type="text" id="msg">
<button id="send" onclick="send()">发送</button>
</p>
<div id="chat_content" ></div>
</div>
</body>
<script type="application/javascript">
var ws = new WebSocket('ws://192.168.16.14:8888/websocket');
var name = null; //向服务端发送本机昵称
function login() {
document.getElementById('login').setAttribute('hidden', 'hidden');
document.getElementById('client_name').setAttribute('disabled', 'disabled');
document.getElementById('chat_msg').removeAttribute('hidden');
document.getElementById('chat_content').removeAttribute('hidden');
name = document.getElementById('client_name').value;
ws.send(name);
}; //监听服务器发来的消息(json数据)
ws.onmessage = function (MessageEvent) {
//console.log(MessageEvent);
//console.log(MessageEvent.data);
var content_str = JSON.parse(MessageEvent.data);
var time = new Date();
var t = time.toLocaleTimeString();
var p = document.createElement("p");
p.innerText = content_str.name + "(" + t + "):" + content_str.msg;
document.getElementById('chat_content').appendChild(p);
}; //聊天信息发送(json数据)
function send() {
var msg = document.getElementById('msg').value;
var data = {
name: name,
msg: msg
};
var data_json = JSON.stringify(data);
ws.send(data_json);
}
</script>
</html>

MUC_nick.html

(3)基于websocket+flask实现的私聊即时通信

  flask_websocket(Private_chat).py

 '''
基于websocket+flask实现的私聊即时通信
设计字典client_dict = {}来存储{客户端的名字:客户端与服务器的连接},客户端的名字通过动态路由参数获取到,
服务器通过客户端发来的信息(经过json序列化后的字典)中的目标客户端名字,在存储字典中获取目标客户端的连接,直接转发
'''
from flask import Flask, render_template, request
from geventwebsocket.handler import WebSocketHandler # 提供WS(websocket)协议处理
from geventwebsocket.server import WSGIServer # websocket服务承载
from geventwebsocket.websocket import WebSocket # websocket语法提示
import json app = Flask(__name__) client_dict = {} @app.route('/websocket/<client_name>') # 通过动态路由参数获取昵称,必须在视图函定义同名形参接收
def websocket(client_name):
client_socket = request.environ.get('wsgi.websocket') # type:WebSocket
client_dict[client_name] = client_socket
if client_socket:
while 1:
msg_from_cli = client_socket.receive()
to_client = json.loads(msg_from_cli).get('to_client')
client = client_dict.get(to_client)
try:
client.send(msg_from_cli)
except Exception as e:
continue @app.route('/chat')
def chat():
return render_template('Private_chat.html') if __name__ == '__main__':
http_server = WSGIServer(('192.168.16.14', 8888), application=app, handler_class=WebSocketHandler)
http_server.serve_forever()

flask_websocket(Private_chat).py

  Private_chat.html  

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>单人聊天室</title> </head>
<body>
<div id="chat_room">
<p>输入昵称进入单人聊天室:<input type="text" id="client_name"></input>
<button id='login' onclick="login()">登录</button>
</p>
<p hidden id="client_recv">收信人:<input type="text" id="to_client"></p>
<p id='chat_msg' hidden="hidden">请输入聊天内容:<input type="text" id="msg"> <button id="send" onclick="send()">发送</button>
</p>
<div id="chat_content" hidden="hidden"></div>
</div>
</body>
<script type="application/javascript">
var ws = null;
var name=null; function login() {
document.getElementById('login').setAttribute('hidden', 'hidden');
document.getElementById('client_name').setAttribute('disabled', 'disabled');
document.getElementById('chat_msg').removeAttribute('hidden');
document.getElementById('chat_content').removeAttribute('hidden');
document.getElementById('client_recv').removeAttribute('hidden'); name = document.getElementById('client_name').value;
//进行WS实例化
ws = new WebSocket('ws://192.168.16.14:8888/websocket/' + name); //监听服务器发来的消息(json数据)
ws.onmessage = function (MessageEvent) {
//console.log(MessageEvent);
//console.log(MessageEvent.data);
var content_str = JSON.parse(MessageEvent.data);
var time = new Date();
var t = time.toLocaleTimeString();
var p = document.createElement("p");
p.innerText = content_str.name + "(" + t + "):" + content_str.msg;
document.getElementById('chat_content').appendChild(p);
};
}; //聊天信息发送(json数据)
function send() {
var msg = document.getElementById('msg').value;
var to_client=document.getElementById('to_client').value;
var data = {
name: name,
msg: msg,
to_client:to_client
}; var data_json = JSON.stringify(data);
ws.send(data_json); var time = new Date();
var t = time.toLocaleTimeString();
var p = document.createElement("p");
p.innerText = name + "(" + t + "):" + msg;
document.getElementById('chat_content').appendChild(p); }
</script>
</html>

Private_chat.html

flask之gevent-websocket的IO多路复用长连接通信的更多相关文章

  1. Netty学习——通过websocket编程实现基于长连接的双攻的通信

    Netty学习(一)基于长连接的双攻的通信,通过websocket编程实现 效果图,客户端和服务器端建立起长连接,客户端发送请求,服务器端响应 但是目前缺少心跳,如果两个建立起来的连接,一个断网之后, ...

  2. 雨露均沾的OkHttp—WebSocket长连接的使用&源码解析

    前言 最近老板又来新需求了,要做一个物联网相关的app,其中有个需求是客户端需要收发服务器不定期发出的消息. 内心OS:

  3. HTTP的长连接和短连接——Node上的测试

        本文主要从实践角度介绍长.短连接在TCP层面的表现,借助Node.JS搭建后台服务,使用WinHTTP.Ajax做客户端请求测试,最后简单涉及WebSocket.     关键字:长连接.短连 ...

  4. HTTP 长连接 使用场景

    offer 80 非常多应用譬如监控.即时通信.即时报价系统都须要将后台发生的变化实时传送到client而无须client不停地刷新.发送请求. 在 多好科技的那位技术指导问我这个是由于他们做物连网, ...

  5. 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

    本文原作者:“水晶虾饺”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.引言 好多小白初次接触即时通讯(比如:IM或者消息推送应用)时,总是不 ...

  6. 微信硬件平台(七) 设备控制控制面板-网页sokect-mqtt长连接

    给微信硬件设备添加我们自己的控制面板. 主要问题: 1 要保证长连接,这样面板可以实时交互阴间设备,http一次性的连接模式通信不行. 面板必须是网页化的,网页就可以操作交互.不用APP和小程序. 2 ...

  7. [转]Web 通信 之 长连接、长轮询(long polling)

    本篇文章转载自Web 通信之长连接.长轮询(longpolling),版权归作者所有. 转者按:随着技术的发展,在HTML5中,可以通过WebSocket技术来完成长连接的开发,虽然如此,本文依然存在 ...

  8. day36 python学习gevent io 多路复用 socketserver *****

    ---恢复内容开始--- gevent 1.切换+保存状态 2.检测单线程下任务的IO,实现遇到IO自动切换 Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在geven ...

  9. gevent协程、select IO多路复用、socketserver模块 改造多用户FTP程序例子

    原多线程版FTP程序:http://www.cnblogs.com/linzetong/p/8290378.html 只需要在原来的代码基础上稍作修改: 一.gevent协程版本 1. 导入geven ...

随机推荐

  1. Windows 版本 Enterprise、Ultimate、Home、Professional

    关于Windows 的安装光盘版本很多种,很多人不知道选择哪些. Ultimate 旗舰版,VISTA开始有了这个级别,是最全最高级的,一般程序开发的电脑,玩游戏的电脑,建议用它,不过对配置稍有一些要 ...

  2. Testing for the End of a File (Windows 的异步 IO)

    The ReadFile function checks for the end-of-file condition (EOF) differently for synchronous and asy ...

  3. 13个Python图形库

    By Django中国社区 at 2013-04-27 07:49 Python的13大图形库,matplotlib功能最强大,Cairoplot最漂亮,django-chartit与Django集成 ...

  4. 阿里大牛带你深入分析spring事务传播行为

    spring框架封装了很多有用的功能和组件,便于在项目开发中快速高效的调用,其中spring的事务使用非常简单,只需要在用到事务的地方加一行注解即可: 1@Transactional 但越是看起来简单 ...

  5. php private学习笔记

    类的权限修饰符,放在属性/方法的前面.用来说明属性/方法的权限特点. 三种权限修饰符 private  私有的 public   公共 protected  保护的 privata 的属性.方法只能在 ...

  6. POJ - 2251 Dungeon Master (搜索)

    You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of un ...

  7. Jenkins 构建 Jmeter 项目之源代码管理(SVN)

    1.查看项目创建中是否又 svn 插件,没有的话下载插件 subversion 2.配置 svn 源代码管理,如下图(testcases 目录下包含 build.xml 和脚本文件) 3.查看 Jen ...

  8. LeetCode 45. 跳跃游戏 II | Python

    45. 跳跃游戏 II 题目来源:https://leetcode-cn.com/problems/jump-game-ii 题目 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素 ...

  9. 安卓commandlinetools-win-6200805_latest配置

    JDK:1.8.0_251 系统:win10 64bit 问题1 官网下载commandlinetools,解压运行报错 解决方法 打开sdkmanager.bat,修改第17行为set DEFAUL ...

  10. weak_ptr

    #include <iostream> #include <memory> using namespace std; int main(int argc, char **arg ...