教程
信息差
资源
软件工具
技术笔记
AIGC
视频
Search
1
使用AI实现高精度钢琴曲转谱Piano Transcription简明使用教程
37,794 阅读
2
使用ESP8266Wifi模块制作Wifi杀手
37,467 阅读
3
unravel 让图片唱歌详细教程 Real Time Image Animation 项目
27,386 阅读
4
佳能相机刷Magic Lantern魔灯固件
23,503 阅读
5
战地3 正版账号免费分享!
16,213 阅读
教程
信息差
资源
软件工具
技术笔记
AIGC
视频
Search
标签搜索
python
前端
环境搭建
空镜素材
Ubuntu
markdown
神器
黑苹果
编码
技巧
Git
数据库
开发
下载工具
Youtube
CDN
PDF
OST
电影原声带
音乐
易小灯塔
累计撰写
176
篇文章
累计收到
44
条评论
首页
栏目
教程
信息差
资源
软件工具
技术笔记
AIGC
视频
页面
搜索到
175
篇与
的结果
2020-09-16
新奇网盘BiliDrive哔哩云使用教程 附部分知识星球精华整理下载
无意中发现了一个新奇的网盘BiliDrive, 分享一下GitHub地址 https://github.com/Hsury/BiliDrive特色轻量:无复杂依赖,资源占用少自由:无文件格式与大小限制,无容量限制安全:上传的文件需要通过生成的META URL才能访问,他人无法随意查看稳定:带有分块校验与超时重试机制,在较差的网络环境中依然能确保文件的完整性快速:支持多线程传输与断点续传,同时借助B站的CDN资源,能最大化地利用网络环境进行上传与下载技术实现将任意文件分块编码为图片后上传至B站,对该操作逆序即可下载并还原文件进化版01 CDNDrive https://github.com/apachecn/CDNDrive使用更简单, 看文档好像还除了b站还支持其他网站, 请自测cdrive login usage: CDNDrive login [-h] {bili,baijia,csdn,sohu,jian,weibo,ali,163,osc,sogou} username password 02 BiliDrive-BT https://github.com/1299172402/BiliDrive-BTBili图床共有库 BiliDrive魔改版 有网盘同步,类bt上传功能模仿bt种子和磁力链接设计使用方法(CDNDrive)安装01 安装python3.6以上版本02 安装CDNDrive通过pip安装pip install CDNDrive 通过源码安装pip install git+https://github.com/apachecn/CDNDrive 登陆cdrive login bili username password username: bilibili用户名 password: bilibili密码 下载cdrive download 网盘地址 下载完毕后会自动进行文件完整性校验,对于大文件该过程可能需要较长时间,若不愿等待可直接退出上传等更详细使用见项目文档https://github.com/apachecn/CDNDrive下面是知识星球精华整理下载新建个文件夹, 空白处按住shift键, 右键点击在此处打开powershell窗口, 把下面地址直接复制粘贴上去回车就可以下载了批量下载脚本使用方法: 新建个文件夹, 在文件夹里新建个list.txt, 把要下载的列表粘贴进去, 再新建个download.py文件, 把下面的脚本粘贴进去, 运行这个py文件import os drive = {"bdex": 47, "wbdrive": 42, "bjdrive": 42, "csdrive": 27, "jsdrive": 33, "shdrive": 51, } file = open("list.txt", "r") for line in file: cmd= '' for k, v in drive.items(): if k in line: index = line.find(k) cmd = "cdrive download " + line[index:(index + v)] print(cmd) else: continue res = os.popen(cmd).read() print(res) file.close() print("全部下载完成!") 「帅张和他的朋友们」第二期精华电子书.pdf (1.49 MB) cdrive download bdex://0f39451b7944df1e8483897753af1ee443ded38c 逸米家知识星球整理 20190916.epub (17.44 MB) cdrive download bdex://8c90c920725eaa67c5822ea451dcffd999cb256b 生财有道商学院知识星球附件 20190611-20191003.pdf (26.50 MB) cdrive download bdex://a9b4282134faf5b3d907f53c2f3caee964e47612 郑州买房知识星球精华 20190521.epub (346.83 KB) cdrive download bdex://8538b01165dbef45cf18e572313a24641fde93f2 愚公掘金知识星球精华 20191125.epub (9.52 MB) cdrive download bdex://ba62de4c20aa07aae231f198a51aadcf38328e2e 「帅张和他的朋友们」第一期精华电子书.pdf (1.06 MB) cdrive download bdex://92de120e5d75ba0594b752982b55c3d3e6838e4b 就聊挣钱知识星球精华 20190828.epub (6.81 MB) cdrive download bdex://a50386a5f1e87f2e364a316b208b6774a86f2b4f 童大焕知识星球整理 20191125.pdf (1.14 MB) cdrive download bdex://32d7f90f61b87c1edad4a1860ebc597d1b984de2 路人甲乙丙知识星球精华 20190916.epub (8.24 MB) cdrive download bdex://54d6866c0d17d38c91f12d2cd68a1eee17807fed 泽宇核心课知识星球精华 20190101-20190830.epub (15.95 MB) cdrive download bdex://e277fbf24d33d2a87620b2ac6b19ade92d8a70c8 曹将和朋友们知识星球精华 20190725.epub (13.75 MB) cdrive download bdex://7462af5edbd687c10214b9ea7c9b965ced526400 小马宋商业观察知识星球精华 20190910.epub (2.15 MB) cdrive download bdex://1d523af42a5af0bf86aeab6f96c9131bb4143b7d 下一站深圳知识星球整理 20190926.epub (4.23 MB) cdrive download bdex://e3a9e135a18055bd34f13ecaafb7c42a1e323850 花神妙知识星球精华 20190828.epub (2.92 MB) cdrive download bdex://0f1b54bbee0bc5008dda92b191fe5ab9fa246920 生财有术知识星球整理 20190928.epub (12.92 MB) cdrive download bdex://4617effa49730b35557743f972c12dc011bfedce 斜杠星球知识星球精华 20190725.epub (3.98 MB) cdrive download bdex://e3ca3d0cb76a80996ecf631284ec8ce76b15e1af 生财有道商学院知识星球整理 20190413-20191006.pdf (15.12 MB) cdrive download bdex://5b6da93313a910c60227b023133f89f51746fd34 童大焕:买房的革命.pdf (551.20 KB) cdrive download bdex://09b98c48d615ec5721d8572c6b0a222b4cc2488f 老 A 的私人空间知识星球整理 20190809.epub (4.19 MB) cdrive download bdex://6667333b4229928beedbac57d26443a003d31f17 刘煜辉经济笔记知识星球整理 201906-201908.pdf (24.72 MB) cdrive download bdex://588303fb9bf491e732aaa68954d83a20b5e54e8f 童大焕:世界越来越陡峭.pdf (2.61 MB) cdrive download bdex://f67f803018db784d8380ecb3dbbd91ffbe65eb88 Affiliate 营销圈知识星球精华 20191125.epub (3.70 MB) cdrive download bdex://7c326aaf7aa11279efb9534078665ad343e311e6 黄章林的升级课知识星球精华 20190909.epub (22.06 MB) cdrive download bdex://47a08d1aeef2d40beb97451dbec8061c6fbfbcec 齐俊杰的粉丝群知识星球精华 2019.pdf (1.74 MB) cdrive download bdex://6f5ce8a5bcd61bb8bd2cfa5e448193c3742e9242 生财日历 2020.pdf (4.24 MB) cdrive download bdex://d99c216b6c614e158b1597ed68c7e602845d1ad8 1000 种赚钱方法知识星球精华 20190828.epub (8.72 MB) cdrive download bdex://7e4ea9ba758264abda2a50837c344c7ee06c06ce 11 点港股打新知识星球整理 20190909.epub (20.13 MB) cdrive download bdex://92034a54ca73af89666504412a95032479d90369 杰哥学霸圈知识星球整理 20190921.epub (8.75 MB) cdrive download bdex://3ae0248240b2a817d72353a8b26a7dfe715db030 Kris 的知识星球精华 20190927.epub (10.82 MB) cdrive download bdex://f8a35e9afe359e8041225b1e1d1a711cd2e329c3 Shopee 大卖之路知识星球整理 20190717.epub (2.97 MB) cdrive download bdex://ff0aa0694424a58aa4032031765f626d089e1829 守夜人总司令知识星球整理 20190916.epub (13.61 MB) cdrive download bdex://8ade1e45d91dd220c64e00d03ba1abdad7edbdd0 精英投资圈知识星球精华 20190628.epub (5.14 MB) cdrive download bdex://5a9a35d044cc97a3e2edf44ecc543657fdf7c0ee 童大焕众筹合集.pdf (2.58 MB) cdrive download bdex://93db72eb0eff656787991d30ff29cd943fb5ad4d 老李的干货笔记知识星球精华 20190908.epub (2.94 MB) cdrive download bdex://1c63755e36e212a0cd01b64412d7bfe96035f50b 清单控沙牛知识星球整理.epub (2.45 MB) cdrive download bdex://b08119acdb583d47a3ce1defae3fc8553cea6414 成年人的第二次大学:愚公掘金电子书.pdf (11.49 MB) cdrive download bdex://7ecf1919a0a4341acf6626810b3ea03a34b57d8a MacTalk 的朋友们知识星球精华 20190725.epub (3.61 MB) cdrive download bdex://7e058364ef7a4202911db896509217d6eaebe4c4 螺丝钉学院知识星球精华 20190809.epub (15.26 MB) cdrive download bdex://eca1a92d5c2fb5a5a282fa3b2d58d03101b78e6a 童大焕 2018 财智书院全集.pdf (6.16 MB) cdrive download bdex://fee7bc9772c74304a9a8f42a7b7743ccc17c28d3 呆叔和他的赚友知识星球整理 20190828.epub (4.70 MB) cdrive download bdex://78edd7f826eef85a71d42f5ce408ef2eaa2133b6 泽宇核心课知识星球精华 2018.epub (21.91 MB) cdrive download bdex://27231607ddb9a0ab0b78bb39e6b5970c57d711a9 Facebook 营销俱乐部知识星球整理 20191016.epub (1.56 MB) cdrive download bdex://5cef194e53f132a87036c3805b70924fa9f4e326 毒辣香蕉的诡秘国度知识星球整理 20190814-20190827.pdf (2.87 MB) cdrive download bdex://02fc8578ef60899356a64027518955fe52957a0e 小道消息知识星球精华 20190719.epub (2.10 MB) cdrive download bdex://710b76d198358ffeb3f6e2f246b0c06f6f5f0781 caoz 的知识星球整理 20190809.epub (14.82 MB) cdrive download bdex://bbd305766273a402e1f726df0492d9ae97541a53 流水白菜知识星球精华 20190907.epub (10.61 MB) cdrive download bdex://d77a62b62a020e6bb9f6d7437e36681f8d40b1c9 郑州新一线知识星球整理 20190523.epub (11.40 MB) cdrive download bdex://1b8dec826a78476aadda659176c3dc8bdc0230f5 电商进化岛知识星球精华 20190724.epub (3.30 MB) cdrive download bdex://9725c9e02bb31308fb48302cf0084c41cbee457f 体制内关系攻略知识星球精华 20190918.epub (713.44 KB) cdrive download bdex://59ae03c756d4ca4b6731cc55833ce3d0d6a1d15f 历史求诸野知识星球整理 20190813.epub (19.64 MB) cdrive download bdex://d1f532099c1c811fd288003e16bb9999b8ad240a 「就聊挣钱」第一期精华电子书.pdf (3.96 MB) cdrive download bdex://eaebc6517bd19e801a128a8cee977dc31f9443b1 粥左罗的知识星球精华 20190829.epub (29.20 MB) cdrive download bdex://4dbb74587b831d6495fa98082fe8527498f68728 猫哥聊地产知识星球精华 20190916.epub (293.67 KB) cdrive download bdex://f7a50c4e9b7e4218ecbb8baa18e402424dab48a1 产品学徒知识星球精华 20190527.epub (588.80 KB) cdrive download bdex://fcb456fcfbcbbf0ae581bb4c0f99e9017ca7ddbe 站在中国财富之巅——风格纯粹VS童大焕云端对话中国三大城市群.pdf (1.77 MB) cdrive download bdex://9c6a042a6758771de01c0a399fcb5527a27cca0f资源由布客飞龙整理上传分享更多电子书资源见他的GitHub: https://github.com/wizardforcel
2020年09月16日
1,726 阅读
0 评论
0 点赞
2020-09-14
免费使用Cloudflare Workers部署服务
简介现在都流行无服务器函数,作为大牌CDN提供商cloud flare自然不甘落后推出了worker服务。免费用户有10万请求/每天 的额度cloudflare注册https://workers.cloudflare.com/作用反向代理镜像网站在线代理加速任意网站建立免费网址导航反向代理addEventListener('fetch', event => { const request = event.request; const url = new URL(request.url); const response = fetch('https://magnetdog.net/' + url.pathname + url.search, { method: request.method, headers: request.headers, body: request.body, }); event.respondWith(response); });建立免费网址导航系统安装在 Cloudflare Worker 管理页面创建一个新的 Worker 。在Worker编辑页面左边粘贴 index.js 中的代码。根据自身需要修改 config 的配置内容Github地址:https://github.com/sleepwood/CF-Worker-Dir/演示地址:http://gethe.best免费部署 JSProxy 服务SProxy 一个基于浏览器端 JS 实现的在线代理,这里不多介绍!本文主要介绍一下利用CloudFlare Worker 来搭建一个JSProxy服务。CloudFlare Worker 是 CloudFlare 的边缘计算服务。开发者可通过 JavaScript 对 CDN 进行编程,从而能灵活处理 HTTP 请求。这使得很多任务可在 CDN 上完成,无需自己的服务器参与。CFW免费服务,支持每天10 万次免费请求!基本也够用了!项目地址:https://github.com/EtherDream/jsproxyCloudflare workers + Github 实现的动态博客系统项目地址 https://github.com/kasuganosoras/cloudflare-worker-blogCloudflare workers + Github 实现的动态博客系统,使用边缘计算,无需服务器用户可以使用 JavaScript 编写自己的程序,然后可以直接通过域名访问运行。获取到自己的**.workers.dev域名 Cname 到(**.workers.dev)然后去 Workers 点击 ADD route输入自定义域名,例如 gd.mjj.com/* 后面要加上 /*,下面的 workers 选择刚才的项目利用 Cloudflare Worker 搭建镜像网站!// 反代目标网站. const upstream = 'google.com' // 反代目标网站的移动版. const upstream_mobile = 'google.com' // 访问区域黑名单(按需设置). const blocked_region = ['TK'] // IP地址黑名单(按需设置). const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] // 路径替换. const replace_dict = { '$upstream': '$custom_domain', '//archiveofourown.org': '' } addEventListener('fetch', event => { event.respondWith(fetchAndApply(event.request)); }) async function fetchAndApply(request) { const region = request.headers.get('cf-ipcountry').toUpperCase(); const ip_address = request.headers.get('cf-connecting-ip'); const user_agent = request.headers.get('user-agent'); let response = null; let url = new URL(request.url); let url_host = url.host; if (url.protocol == 'http:') { url.protocol = 'https:' response = Response.redirect(url.href); return response; } if (await device_status(user_agent)) { var upstream_domain = upstream; } else { var upstream_domain = upstream_mobile; } url.host = upstream_domain; if (blocked_region.includes(region)) { response = new Response('Access denied: WorkersProxy is not available in your region yet.', { status: 403 }); } else if(blocked_ip_address.includes(ip_address)){ response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', { status: 403 }); } else{ let method = request.method; let request_headers = request.headers; let new_request_headers = new Headers(request_headers); new_request_headers.set('Host', upstream_domain); new_request_headers.set('Referer', url.href); let original_response = await fetch(url.href, { method: method, headers: new_request_headers }) let original_response_clone = original_response.clone(); let original_text = null; let response_headers = original_response.headers; let new_response_headers = new Headers(response_headers); let status = original_response.status; new_response_headers.set('cache-control' ,'public, max-age=14400') new_response_headers.set('access-control-allow-origin', '*'); new_response_headers.set('access-control-allow-credentials', true); new_response_headers.delete('content-security-policy'); new_response_headers.delete('content-security-policy-report-only'); new_response_headers.delete('clear-site-data'); const content_type = new_response_headers.get('content-type'); if (content_type.includes('text/html') && content_type.includes('UTF-8')) { original_text = await replace_response_text(original_response_clone, upstream_domain, url_host); } else { original_text = original_response_clone.body } response = new Response(original_text, { status, headers: new_response_headers }) } return response; } async function replace_response_text(response, upstream_domain, host_name) { let text = await response.text() var i, j; for (i in replace_dict) { j = replace_dict[i] if (i == '$upstream') { i = upstream_domain } else if (i == '$custom_domain') { i = host_name } if (j == '$upstream') { j = upstream_domain } else if (j == '$custom_domain') { j = host_name } let re = new RegExp(i, 'g') text = text.replace(re, j); } return text; } async function device_status (user_agent_info) { var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; var flag = true; for (var v = 0; v < agents.length; v++) { if (user_agent_info.indexOf(agents[v]) > 0) { flag = false; break; } } return flag; }const upstream = '反代目标网站'const upstream_mobile = '反代目标网站的移动版'const blocked_region = ['访问区域黑名单(按需设置)']const blocked_ip_address = ['IP地址黑名单(按需设置)', '127.0.0.1']const replace_dict= 路径替换在 CF Workers 搭建自己的 t.cn 短网址入口addEventListener('fetch', (event) => { return event.respondWith(handleRequest(event.request)); }) const handleRequest = async (request) => { const render = (body) => { return new Response(` <!doctype html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>T.CN 短网址</title> </head> <body>${body}</body> </html>`.trim(), { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' } }); } request = new URL(request.url); if (request.pathname !== '/') return new Response(null, { status: 404 }); if (request.searchParams.has('url')) { const url = request.searchParams.get('url'); const response = await fetch(`http://service.weibo.com/share/share.php?url=${encodeURIComponent(url)}&title=1`); const html = await response.text(); const short = html.match(/http:\/\/t.cn\/\w+/i); const refer = html.match(/\$refer\s+: "(.+?)"/i); if (short && refer) { return render(` 缩短结果:<a href="${short[0]}">${short[0]}</a><br /> 原始网址:<a href="${refer[1]}">${refer[1]}</a><br /> <a href="/">返回</a> `); } return render(`请求失败`); } return render(` <form method="GET"> <input name="url" placeholder="URL" /> <button type="submit">压缩</button> </form> `); }改进版 addEventListener('fetch', (event) => { return event.respondWith(handleRequest(event.request)); }) const handleRequest = async (request) => { const render = (body) => { return new Response(` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>T.CN 短网址</title> <style media="screen"> body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; } #message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px; border-radius: 3px; } #message h2 { color: rgba(0,0,0,0.6); font-weight: bold; font-size: 14px; margin: 0 0 8px; } #message h1 { color: #ffa100; font-size: 30px; font-weight: 300; margin: 0 0 16px;} #message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; } #message a { display: block; text-align: center; background: #039be5; text-decoration: none; color: white; padding: 16px; border-radius: 4px; } #message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); } #load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; } @media (max-width: 600px) { body, #message { margin-top: 0; background: white; box-shadow: none; } body { border-top: 16px solid #ffa100; } } </style> </head> <body> ${body} </body> </html>`.trim(), { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' } }); } request = new URL(request.url); if (request.pathname !== '/') return new Response(null, { status: 404 }); if (request.searchParams.has('url')) { const url = request.searchParams.get('url'); const response = await fetch(`http://service.weibo.com/share/share.php?url=${encodeURIComponent(url)}&title=1`); const html = await response.text(); const short = html.match(/http:\/\/t.cn\/\w+/i); const refer = html.match(/\$refer\s+: "(.+?)"/i); if (short && refer) { return render(` <div id="message" align="center"> <center><h1>缩短结果:</h1><a href="${short[0]}">${short[0]}</a></center> <p></p> <center><h1>原始网址:</h1><a href="${refer[1]}">${refer[1]}</a></center> <p></p> <a href="/">返回</a> </div> `); } return render(` <div id="message" align="center"> <center><h1>请求失败</h1></center> </div> `); } return render(` <div id="message" align="center"> <center><h1>T.CN 短网址</h1></center> <p></p> <form method="GET"> <input name="url" placeholder="URL" /> <button type="submit">压缩</button> </form> </div> `); }
2020年09月14日
1,356 阅读
0 评论
2 点赞
2020-09-13
Django的流量控制
APIView会在进行dispatch()分发前,对请求进行身份认证、权限检查、流量控制对接口访问的频次进行限制,减少对服务器的压力在settings.py添加一个REST_FRAMEWORK字典REST_FRAMEWORK = { "DEFAULT_THROTTLE_CLASS":( 'rest_framework.throttling.AnonRateThrottle',#未登录用户 'rest_framework.throttling.UserRateThrottle'#登录用户 ), "DEFAULT_THROTTLE_RATES':{ 'anon':'100/day', #未登录用户 每天100次 'user':'1000/day' #登录用户 每天1000次 } } #DEFAULT_THROTTLE_RATES也可以使用second,minutes,hour或day指明周期 指明指定视图的访问次数:class ContactListView(APIView): throttle_scope = 'contacts' class ContactDetailView(APIView): throttle_scope = 'contacts' class UploadView(APIView): throttle_scope = 'uploads' REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES':( 'rest_framework.throttling.ScopedRateThrottle', ), 'DEFAULT_THROTTLE_RATES':{ 'contacts':'1000/day', 'uploads':'20/day' } }
2020年09月13日
6,279 阅读
0 评论
0 点赞
2020-09-11
接口幂等性设计
接口幂等性设计 概述幂等性是什么?幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。接口为什么要实现幂等? 前端重复提交选中的数据,后台只产生对应这个数据的一个反应结果。 使用幂等的场景1.前端重复提交用户注册,用户创建商品等操作,前端都会提交一些数据给后台服务,后台需要根据用户提交的数据在数据库中创建记录。如果用户不小心多点了几次,后端收到了好几次提交,这时就会在数据库中重复创建了多条记录。这就是接口没有幂等性带来的 bug。2.接口超时重试对于给第三方调用的接口,有可能会因为网络原因而调用失败,这时,一般在设计的时候会对接口调用加上失败重试的机制。如果第一次调用已经执行了一半时,发生了网络异常。这时再次调用时就会因为脏数据的存在而出现调用异常。3.消息重复消费在使用消息中间件来处理消息队列,且手动 ack 确认消息被正常消费时。如果消费者突然断开连接,那么已经执行了一半的消息会重新放回队列。当消息被其他消费者重新消费时,如果没有幂等性,就会导致消息重复消费时结果异常,如数据库重复数据,数据库数据冲突,资源重复等 接口幂等性实现思路1.Token机制当客户端请求页面时,服务器会生成一个随机数token,并且将token放置到session当中,然后将token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,token会随着表单一起提交到服务器端。服务器端第一次验证相同过后,会将session中的token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的token没变,但服务器端session中token已经改变了。具体流程步骤: 客户端会先发送一个请求去获取 token,服务端会生成一个全局唯一的 ID 作为 token 保存在 redis 中,同时把这个 ID 返回给客户端 客户端第二次调用业务请求的时候必须携带这个 token 服务端会校验这个 token,如果校验成功,则执行业务,并删除 redis 中的 token 如果校验失败,说明 redis 中已经没有对应的 token,则表示重复操作,直接返回指定的结果给客户端 2.数据库联合唯一约束插入数据,应该按照唯一索引进行插入,比如:订单号,相同的订单号就不能有两条记录插入。 我们在数据库层面防止重复。这个机制是利用了数据库的主键唯一约束的特性,解决了在insert场景时幂等问题。 但主键的要求不是自增的主键,这样就需要业务生成全局唯一的主键。 如果是分库分表场景下,路由规则要保证相同请求下,落在同一个数据库和同一表中,要不然数据库约束就不起 效果了,因为是不同的数据库和表主键不相关具体流程步骤: 建立一张去重表,其中某个字段需要建立唯一索引 客户端去请求服务端,服务端会将这次请求的一些信息插入这张去重表中 因为表中某个字段带有唯一索引,如果插入成功,证明表中没有这次请求的信息,则执行后续的业务逻辑 如果插入失败,则代表已经执行过当前请求,直接返回
2020年09月11日
858 阅读
0 评论
0 点赞
2020-09-03
利用CloudflareWorkers加速Github
参考资料https://www.hostloc.com/forum.php?mod=viewthread&tid=737012&highlight=Workers https://github.com/hunshcn/gh-proxy使用国内的云服务器时,对于Github是极其不友好的,经常无法连接上,raw.githubusercontent.com域名也是已经凉凉,git clone能连上的时候也是龟速。Cloudflare Workers免费套餐的每天10万请求数是绰绰有余的使用方法加速下载文件打开https://git.haoduck.cf,然后输入要加速的链接(release文件等)加速clone将git clone https://github.com/username/xxx.git换成git clone https://git.haoduck.cf/github.com/username/xxx.git'use strict' /** * static files (404.html, sw.js, conf.js) */ const ASSET_URL = 'https://hunshcn.github.io/gh-proxy' // 前缀,如果自定义路由为example.com/gh/*,将PREFIX改为 '/gh/',注意,少一个杠都会错! const PREFIX = '/' // git使用cnpmjs镜像、分支文件使用jsDelivr镜像的开关,0为关闭,默认开启 const Config = { jsdelivr: 1, cnpmjs: 1 } /** @type {RequestInit} */ const PREFLIGHT_INIT = { status: 204, headers: new Headers({ 'access-control-allow-origin': '*', 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS', 'access-control-max-age': '1728000', }), } /** * @param {any} body * @param {number} status * @param {Object<string, string>} headers */ function makeRes(body, status = 200, headers = {}) { headers['access-control-allow-origin'] = '*' return new Response(body, {status, headers}) } /** * @param {string} urlStr */ function newUrl(urlStr) { try { return new URL(urlStr) } catch (err) { return null } } addEventListener('fetch', e => { const ret = fetchHandler(e) .catch(err => makeRes('cfworker error:\n' + err.stack, 502)) e.respondWith(ret) }) /** * @param {FetchEvent} e */ async function fetchHandler(e) { const req = e.request const urlStr = req.url const urlObj = new URL(urlStr) let path = urlObj.searchParams.get('q') if (path) { return Response.redirect('https://' + urlObj.host + PREFIX + path, 301) } // cfworker 会把路径中的 `//` 合并成 `/` path = urlObj.href.substr(urlObj.origin.length + PREFIX.length).replace(/^https?:\/+/, 'https://') const exp1 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:releases|archive)\/.*$/i const exp2 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:blob)\/.*$/i const exp3 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:info|git-).*$/i const exp4 = /^(?:https?:\/\/)?raw\.githubusercontent\.com\/.+?\/.+?\/.+?\/.+$/i if (path.search(exp1) === 0 || !Config.cnpmjs && (path.search(exp3) === 0 || path.search(exp4) === 0)) { return httpHandler(req, path) } else if (path.search(exp2) === 0) { if (Config.jsdelivr){ const newUrl = path.replace('/blob/', '@').replace(/^(?:https?:\/\/)?github\.com/, 'https://cdn.jsdelivr.net/gh') return Response.redirect(newUrl, 302) }else{ path = path.replace('/blob/', '/raw/') return httpHandler(req, path) } } else if (path.search(exp3) === 0) { const newUrl = path.replace(/^(?:https?:\/\/)?github\.com/, 'https://github.com.cnpmjs.org') return Response.redirect(newUrl, 302) } else if (path.search(exp4) === 0) { const newUrl = path.replace(/(?<=com\/.+?\/.+?)\/(.+?\/)/, '@$1').replace(/^(?:https?:\/\/)?raw\.githubusercontent\.com/, 'https://cdn.jsdelivr.net/gh') return Response.redirect(newUrl, 302) } else { return fetch(ASSET_URL + path) } } /** * @param {Request} req * @param {string} pathname */ function httpHandler(req, pathname) { const reqHdrRaw = req.headers // preflight if (req.method === 'OPTIONS' && reqHdrRaw.has('access-control-request-headers') ) { return new Response(null, PREFLIGHT_INIT) } let rawLen = '' const reqHdrNew = new Headers(reqHdrRaw) let urlStr = pathname if (urlStr.startsWith('github')) { urlStr = 'https://' + urlStr } const urlObj = newUrl(urlStr) /** @type {RequestInit} */ const reqInit = { method: req.method, headers: reqHdrNew, redirect: 'follow', body: req.body } return proxy(urlObj, reqInit, rawLen, 0) } /** * * @param {URL} urlObj * @param {RequestInit} reqInit */ async function proxy(urlObj, reqInit, rawLen) { const res = await fetch(urlObj.href, reqInit) const resHdrOld = res.headers const resHdrNew = new Headers(resHdrOld) // verify if (rawLen) { const newLen = resHdrOld.get('content-length') || '' const badLen = (rawLen !== newLen) if (badLen) { return makeRes(res.body, 400, { '--error': `bad len: ${newLen}, except: ${rawLen}`, 'access-control-expose-headers': '--error', }) } } const status = res.status resHdrNew.set('access-control-expose-headers', '*') resHdrNew.set('access-control-allow-origin', '*') resHdrNew.delete('content-security-policy') resHdrNew.delete('content-security-policy-report-only') resHdrNew.delete('clear-site-data') return new Response(res.body, { status, headers: resHdrNew, }) }
2020年09月03日
2,093 阅读
0 评论
0 点赞
2020-08-20
Vultr自定义ISO安装Windows系统镜像提供下载地址
http://down.80host.com/iso/最多两个自定义iso iso需要制作添加驱动使用下面的评估序列号激活Svr 2008 R2 可以获取180天试用期Windows Server 2008 R2 Web: KBV3Q-DJ8W7-VPB64-V88KG-82C49Windows Server 2008 R2 Standard: 4GGC4-9947F-FWFP3-78P6F-J9HDRWindows Server 2008 R2 Enterprise: 7PJBC-63K3J-62TTK-XF46D-W3WMDWindows Server 2008 R2 Datacenter: QX7TD-2CMJR-D7WWY-KVCYC-6D2YT在180天试用期即将结束时,在命令行模式下,输入“slmgr.vbs /rearm”后,重启电脑,重新输入上面的序列号,剩余时间又恢复到180天。微软官方文档中声明该命令只能重复使用5次。上面的方法5次后,此后将无法再次使用。就要进行下一步,修改注册表中的一处键值(SkipRearm),以后就可以再次使用“Rearm”的命令,这个键值总共可以修改8次。DD方式安装windows20032008r2http://arv.asuhu.com/cn_windows_server_2008_r2_standard_enterprise_datacenter_and_web_with_sp1_vl_build_x64_dvd_617396_virtio_20180125.iso2016http://arv.asuhu.com/cn_windows_server_2016_x64_dvd_9327743_virtio_20170124.isowin10http://arv.asuhu.com/cn_windows_10_multi-edition_vl_version_1709_updated_dec_2017_x64_dvd_100406208_virtio_20180202.iso
2020年08月20日
1,497 阅读
2 评论
0 点赞
2020-08-18
VPS/云服务器测速网速综合shell测速脚本 – Superspeed.sh – 测试本地实际速度
VPS/云服务器测速网速综合shell测速脚本 – Superspeed.sh – 测试本地实际速度买服务器的,需要测速的可以用到这个VPS/云服务器测速网速综合shell测速脚本包含更多更新测速节点的一键测速脚本 Superspeed.shGithub (https://github.com/ernisn/superspeed) |测速节点列表 (https://github.com/ernisn/superspeed/blob/master/ServerList.md)使用:bash <(curl -Lso- https://git.io/superspeed)涵盖了国内各方位的三大运营商测速点,可以较为客观地反映到国内的速度一键测速脚本Superspeed.sh是一个包含了更多国内电信联通移动测速节点的Linux系统带宽速度测试脚本,能比较全面的测试Linux系统服务器到国内电信、联通、移动节点的上行(上传)、下行(下载)速度。一键测速脚本Superspeed.sh是有大佬基于Oldking制作的国内速度测试脚本进行修改了,优势是比较全面的增加了国内电信、联通、移动线路测试节点。其实蜗牛也基于Oldking制作的国内速度测试脚本做过修改,也就是蜗牛发布测评文章当中比较常用到的。这里蜗牛都在此文章当中记录下,方便有需要的博友使用<(curl -Lso- https://git.io/superspeed) #蜗牛备份脚本 <(curl -Lso- https://raw.githubusercontent.com/wn789/ernisnsuperspeed/master/superspeed.sh)二、蜗牛修改版 蜗牛修改了两个版本,一个是测试国内节点,一个是测试国外节点。 1、国内节点测试脚本wget -qO- --no-check-certificate https://raw.githubusercontent.com/wn789/Superspeed/master/superbench.sh #或 curl -Lso- -no-check-certificate https://raw.githubusercontent.com/wn789/Superspeed/master/superbench.sh 2、国际节点测试脚本wget -qO- --no-check-certificate https://raw.githubusercontent.com/wn789/Superspeed/master/superbench_hw.sh #或 curl -Lso- -no-check-certificate https://raw.githubusercontent.com/wn789/Superspeed/master/superbench_hw.sh 小鸡信息检查脚本wget -q https://github.com/Aniverse/A/raw/i/a && bash asuperbenchwget -qO- --no-check-certificate https://raw.githubusercontent.com/oooldking/script/master/superbench.sh | bash自建speedtest测试这个适合VPS主机商,方便给客户测试从服务器到用户本地的下载速度。项目主页:https://github.com/adolfintel/speedtest
2020年08月18日
965 阅读
0 评论
0 点赞
2020-08-15
类Notion云端笔记/个人知识库:
我来/wolai 是一个类Notion在线云端笔记, 用来信息组织与协同的工具, 管理自己的知识库支持markdown, 自带图床,也可以使用自己的图床, 目前不可外链, 有导出分享需求的可以使用自己的图床,需要说一下就是markdown里的表格目前暂时不可用(后续会开发)现在用来做typora的替代, 能比普通笔记更好的组织知识, 中文本土化 有使用问题可以进内测群提问 点击查看内测群官方地址 https://www.wolai.com/目前内测中, 注册需要邀请码, 现献上邀请码一枚: NZNJYM3 注意使用次数有限的, 请尽快使用 移动端和PC自适应, 直接输入wol.ai或wolai.com访问iOS/Android 客户端正在开发中Mac/Windows/客户端下载地址https://github.com/wolfstark/wolai-client/releases Wolai/我来 云端笔记 使用文档使用键盘快捷键可大幅提升编辑效率。我们将尽量使得所有编辑操作都能通过键盘完成,使你成为真正的“键盘侠”。cmd/ctrl表示在Mac系统中按command键,在Windows系统中按ctrl键;opt/shift表示在Mac系统中按option键,在Windows系统中按shift键。全局cmd/ctrl + \ 收起或打开侧边栏cmd/ctrl + S保存更改(不按也会随时保存)cmd/ctrl + [ 返回上一页(后退)cmd/ctrl + ] 期望下一页(前进)cmd/ctrl + P显示/关闭搜索 和最近浏览页面列表cmd/ctrl + shift + P显示/关闭页面关系图ctrl + cmd + space打开Emoji表情窗口 (Mac)win + . 或者 win + ; 打开Emoji表情窗口 (Windows)cmd + opt + G打开/关闭Good Night模式 (Mac)ctrl + alt + G打开/关闭Good Night模式 (Windows)cmd/ctrl + shift + U显示/隐藏块结构虚线框cmd/ctrl + shift + L启用/关闭悬浮目录编辑器操作编辑器的基本键盘操作。编辑时enter在光标位置处另起一行(新建块),选中块时enter切换为光标输入状态编辑时shift + enter软回车,在同一个段落(块)内进行换行cmd/ctrl + Z撤销上一次操作cmd/ctrl + shift + Z重做上一次操作tab缩进一层,请浏览缩进与取消缩进shift + tab取消缩进一层,请浏览缩进与取消缩进esc选中当前块/取消选中cmd/ctrl + / 打开块菜单,可对当前选中块进行操作cmd/ctrl + D克隆当前块(段落)的副本出来shift + ↑ ↓ → ← 选中文本,无法选中更多文本时选中块(段落)↑ ↓ 编辑时上下移动光标,选中块时上下移动切换选择选中块时shift + ↑ ↓ 可上下多选cmd/ctrl + shift + ↑ ↓ 上移、下移当前块或选中块cmd/ctrl + a有光标时选中文本,否则选中所有块(段落)选中块时backspace或者del可删除块有光标时backspace删除光标前文本有光标时del删除光标后文本文本样式选中文本时cmd/ctrl + B变为粗体样式,非选中情况下则设定之后输入的文字为粗体。选中文本时cmd/ctrl + I变为斜体样式,非选中情况下则设定之后输入的文字为斜体。选中文本时cmd/ctrl + U变为下划线样式,非选中情况下则设定之后输入的文字为下划线样式。选中文本时cmd/ctrl + shift + S变为删除线样式,非选中情况下则设定之后输入的文字为删除线样式。选中文本时cmd/ctrl + E变为行内代码样式选中文本时cmd/ctrl + shift + X变为行内公式选中文本时cmd/ctrl + shift + H套用最近设置的字体颜色cmd/ctrl + enter:在或选中待办列表时,可勾选/取消勾选 在或选中折叠列表时,可展开/折叠 在代码片段中可以跳出 选中页面时,进入页面 选中图片时,进入/退出全屏(即将)快速转换cmd/ctrl + opt/shift + 0将当前块转换为文本块cmd/ctrl + opt/shift + 1将当前块转换为主标题(H1)cmd/ctrl + opt/shift + 2将当前块转换为大标题(H2)cmd/ctrl + opt/shift + 3将当前块转换为中标题(H3)cmd/ctrl + opt/shift + 4将当前块转换为小标题(H4)cmd/ctrl + opt/shift + 5将当前块转换为待办列表cmd/ctrl + opt/shift + 6将当前块转换为列表cmd/ctrl + opt/shift + 7将当前块转换为数字列表cmd/ctrl + opt/shift + 8将当前块转换为折叠列表cmd/ctrl + opt/shift + 9将当前块转换为子页面cmd/ctrl + opt/shift + -将当前块 转换为代码片段cmd/ctrl + opt/shift + +将当前块转换为数学公式在行首输入 [] ,即可创建一个待办列表项(全角“【】”亦可)在行首输入1. 跟随空格,创建一个数字列表项,若在某个数字列表项下方,应输入下一个数字方能转换在行首输入 * 或 - 或 + 跟随空格,快速创建一个列表项在行首输入 " 跟随空格,创建一个引述文字块在行首输入 > 跟随空格,创建一个折叠列表在行首或结尾输入 ---,创建一条分割线在行首输入 `````(数字1左边的键)跟随空格或回车创建一个代码片段也可在杭行首输入 lang跟随空格或回车创建指定语言的代码片段,例如:js在行首输入 !! 跟随空格,创建一个着重文字块(即将)在文字两边输入 **,__ 则变为粗体。(与前面内容需要空格,且顺序输入)在文字两边输入 *, _ 则变为斜体。(与前面内容需要空格,且顺序输入)在文字两边输入 ~ 则变为删除线。(与前面内容需要空格,且顺序输入)字符转换输入 --,转换为 — 符号输入 ->,转换为 → 符号输入 <-,转换为 ← 符号输入 >=,转换为 ≥ 符号输入 <=,转换为 ≤ 符号输入 !=,转换为 ≠ 符号快捷菜单快捷菜单支持通过命令匹配即可选中相应的操作以提升键盘操作的效率,以下所列是最高效率的输入,但可能不是唯一的方式。例如“新建文本块”,既可以 /wb,也可以 /wenben,/text或者 /文本。注意:所有快捷菜单的命令都需要输入后按下回车生效。新建块/wb新建文本块/db新建待办列表/zbt新建主标题/dbt新建大标题/zhbt新建中标题/xbt新建小标题/ym新建子页面/wxlb新建列表(无序列表)/sz新建数字列表(有序列表)/img, /tp新建一个图片块/fi, /wj新建一个文件块块转换输入 /zh或者 /zhw,再继续输入块名称简写,即可快速选中。/zhwb转换当前块为文本/zhdb转换当前块为待办列表/zhzbt转换当前块为主标题/zhdbt转换当前块为大标题/zhzhbt转换当前块为中标题/zhxbt转换当前块为小标题/zhym转换为页面/zhlb转换为列表颜色颜色筛选/last选择最近一次使用的颜色/fc筛选所有文字色/bgc筛选所有背景色文字颜色/hui选择灰色文字色/zs选择棕色文字色/chs选择橙色文字色/yel选择黄色文字色/lv选择绿色文字色/lan选择蓝色文字色/zs选择紫色文字色/fs选择粉色文字色/red选择红色文字色/any选择暗银背景色/yx选择幼杏背景色/xj选择鲜橘背景色/danhua选择淡黄背景色/ql选择浅绿背景色/tian选择天蓝背景色/wul选择雾蓝背景色引用链接请浏览引用链接。编辑时输入 [[ 即可搜索一个页面后,添加该页面的引用链接编辑时输入 # 即可搜索一个页面后,添加该页面的引用链接(#前面需空格)选中文本后cmd/ctrl + shift + R快速创建引用链接图标选择窗口cmd/ctrl + opt/shift + 0随机选择一个表情/图cmd/ctrl + opt/shift + - 移除页面图标↑ ↓ → ← 移动并高亮图标页面关系图请浏览页面关系图。cmd/ctrl + shift + P打开/关闭页面关系图space将视图调整为最佳视图enter快速切换到搜索框输入光标esc关闭页面关系图shift + click同时选中多个节点cmd/ctrl + click显示选中节点所在的整个子网络关系图单页面页面关系图space将视图调整为最佳视图esc关闭页面关系图
2020年08月15日
6,556 阅读
2 评论
1 点赞
2020-07-18
Fiddler配合安卓模拟器实现APP的Https抓包
Fiddler配合安卓模拟器实现APP的Https抓包简介Fiddler抓包功能非常强大,可非常便捷得对包进行断点跟踪和回放, 手机的APP和后台通信很多都是基于https的, 需要特殊的设置, 不然是抓不到的.Fiddler的抓包原理是通过设置一个代理服务器, 让APP或网站通过这个代理访问网站, 从而监听到访问数据. https的数据需要一个可信任的证书, Fiddler可以生成证书, 安装好证书就可以监听到https数据了, 下面就来介绍怎么安装证书需要用的软件fiddler 网上下载一个即可有root权限的手机或安卓模拟器 很多手机root都比较麻烦, 这里选择安卓模拟器来做演示, 原理一样的, 网上下载个逍遥,夜神安卓模拟器即可安卓文件浏览器 能访问系统文件的, 如re文件浏览器等1.获取证书文件1.1 导出证书打开 fiddler在设置项中找到Tools->Fiddler Options->HTTPS按图片设置导出证书到桌面1.2 用命令行转换证书在证书所在的目录打开CMD命令行转化证书格式为pemopenssl x509 -inform DER -in FiddlerRoot.cer -out cacert.pem 计算证书hash并改名openssl x509 -inform PEM -subject_hash -in cacert.pem 计算结果若为269953fb 将cacert.pem改命为 269953fb.02.安装证书文件2.1 将证书文件复制到安卓模拟器打开安卓模拟器, 把刚才的 269953fb.0文件复制到模拟器共享文件夹2.2 将证书文件复制到安卓系统证书目录打开re文件管理器, 找到download目录, 找到刚才的 269953fb.0文件复制到证书文件夹/system/etc/security/cacerts 里, 证书就安装成功了2.3 检查证书是否安装成功安卓模拟器上打开设置-> 安全 -> 信任的凭据 看到如下 所示则代表证书已经安装成功了3.配置监听抓包3.1 fiddler的设置打开Fiddler设置代理Tools –> Fiddler Options –> HTTPS3.2 安卓模拟器设置安卓模拟器长安WiFi图标, 点击修改网络填入代理, ip为你自己电脑局域网ip(可通过局域网ipconfig查看), 保存即可3.3 测试抓包在浏览器中输入https://www.baidu.com/#, 或打开app, 就可在fiddler看到在抓到的https包了结尾其实App的http抓包不难, 只是证书安装稍微麻烦, 其他抓包软件比如Charles大概也是这么一个流程, iOS也是差不多的教程
2020年07月18日
2,620 阅读
0 评论
0 点赞
2020-06-16
如何开发一套 VPN
简介这篇文章讲的是如何开发一套VPN, 不是如何使用某个 VPN.一套, 包括Linux服务端, 安卓客户端, Windows客户端.VPN 一般用于实现访问局域网, 当然也可以有其他用途.VPN 协议特征过于明显, 很容易被识别并封禁, 本文主要是介绍原理, 有兴趣的同学可以基于此优化.咦? 为什么会有人要识别和封禁 VPN 呢? 我也布吉岛…1. VPN 的原理以下会描述得比较通俗, 不太专业, 请专业人士见谅, 也欢迎您指正.1.1 Linux 服务端如果Linux有两张网卡, K1 和 K2, 其中 K1 可以上网, K2 不可以.我们可以设置 Linux 使它将 K2 收到的流量转向 K1, 让 K1 帮把 K2 的流量转发出去, 等到数据回来到 K1 时, K1 再转给 K2.这就是路由器的工作原理.我们购买到的 VPS 一般只有一张上网的网卡, 这时, 我们需要创建一张虚拟网卡.VPN 服务程序只需要将从客户端收到的数据写入 K2, 再从 K2 读取回包, 再发回给客户端就行.1.2 安卓客户端安卓提供了一个方法, 可以新建一个虚拟网卡, 叫做 tun, 然后让所有 app 的网络连接都发到 tun.然后让某个 app 可以对发到这张虚拟网卡的流量进行管理.这个可以管理虚拟网卡流量的 app 就是 VPN 客户端 app.VPN 客户端 app 只需要将从 tun 读取到的数据发向服务端, 等服务端回包时, 再将数据写入 tun 就行.1.3 Windows 客户端Windows 可以安装第三方虚拟网卡.我们可以让程序修改路由表, 使得流量转向虚拟.客户端程序对虚拟网卡进行监听, 读取住转向虚拟网卡的流量.客户端程序只需要将从虚拟网卡读取到的数据发向服务端, 等服务端回包时, 再将数据写入虚拟网卡就行.2. 服务端开发2.1 Linux以下命令均需要root权限执行.一. 首先我们要设置 Linux 的 ip_forward. 使它能在不同网卡间转发流量.# 编辑这个文件: vim /etc/sysctl.conf # 将文件里的这行取消注释 # net.ipv4.ip_forward = 1 # 然后执行这条命令: sysctl -p # 如果有看到 net.ipv4.ip_forward = 1 说明成功了.二. 需要新建一个虚拟网卡, 并设置它的ip, 以及设置将其流量转发到真实网卡. 一般命名为 tun0, tun1, tun2…ip tuntap add tun0 mode tun ip link set dev tun0 up ifconfig tun0 192.168.194.224 netmask 255.255.255.0 promisc iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # 第一步有可能遇到如下错误: # Object "tuntap" is unknown, try "ip help". # 解决方法: 使用tunctl添加tun # Unbuntu: apt-get install uml-utilities bridge-utils # CentOS: yum install tunctl brctl # 执行下面这条命令后继续第二步 tunctl -n -t tun0 -u root三. 关键代码 (使用udp进行服务端和客户端间的数据传输)// 打开虚拟网卡 tun0, 获取文件描述符 tun_fd int tun_fd; char *clonedev = "/dev/net/tun"; if ((tun_fd = open(clonedev, O_RDWR)) < 0) { printf("error1"); return -1; } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; strncpy(ifr.ifr_name, "tun0", IFNAMSIZ); int err; if ((err = ioctl(tun_fd, TUNSETIFF, (void *) &ifr)) < 0) { close(tun_fd); return err; } uint8_t buf[MAX_PKG_LEN] = { 0 }; struct sockaddr_in* clent_addr; // 将收到的数据写入 tun0 int n = recvfrom(udp_fd, buf, MAX_PKG_LEN, 0, (struct sockaddr*)clent_addr, &len); write(tun_fd, buf, n); // 读取 tun0 收到的回包并发回客户端 int n = read(tun_fd, buf, MAX_PKG_LEN); sendto(udp_fd, buf, n, 0, clent_addr, sizeof(struct sockaddr_in));四. 完整代码vpn-server代码完全使用 C 语言编程.使用 epoll 进行文件描述符管理.为了方便演示没有对数据进行加密, 在实际使用中必须加密!3. 客户端开发3.1 安卓一. 关键代码://请求打开vpn Intent intent = VpnService.prepare(MainActivity.this); if (intent != null) { startActivityForResult(intent, 0); } else { onActivityResult(0, RESULT_OK, null); } //用户同意后,开启vpn服务 @SuppressLint("ResourceAsColor") protected void onActivityResult(int request, int result, Intent data) { super.onActivityResult(request, result, data); if (result == RESULT_OK) { Intent intent = new Intent(this, MyVpnService.class); startService(intent); } } import android.net.VpnService; public class MyVpnService extends VpnService { ... } static String SERVER_ADDR = "192.168.1.169"; static int SERVER_PORT = 7194; static int MAX_BKG_LEN = 65535; @Override public int onStartCommand(Intent intent, int flags, int startId) { Builder builder = new Builder(); builder.setSession("MyVPNService"); builder.addAddress("192.168.194.1", 24); //这个ip要和服务器的虚拟网卡ip在同一个网段 builder.addDnsServer("8.8.8.8"); builder.addRoute("0.0.0.0", 0); static ParcelFileDescriptor mInterface = builder.establish(); FileInputStream in = new FileInputStream(mInterface.getFileDescriptor()); FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor()); InetAddress serverAddr = InetAddress.getByName(SERVER_ADDR); DatagramSocket sock = new DatagramSocket(); sock.setSoTimeout(0); //超时为无穷大 protect(sock); //保护这个连接的数据不会进入虚拟网卡 //启动两个线程一收一发 return START_STICKY } //发线程 @Override public void run() { int length; byte[] ip_pkg = new byte[MAX_BKG_LEN]; while ((length = in.read(ip_pkg)) >= 0) { if (length == 0) { continue; } DatagramPacket msg = new DatagramPacket( ip_pkg, length, serverAddr, SERVER_PORT); sock.send(msg); } in.close(); } //收线程 @Override public void run() { byte[] ip_buf = new byte[MAX_BKG_LEN]; while (true) { DatagramPacket msg_r = new DatagramPacket( ip_buf, MAX_BKG_LEN, serverAddr, SERVER_PORT); sock.receive(msg_r); int pkg_len = msg_r.getLength(); if (pkg_len == 0) { continue; } else if (pkg_len < 0) { break; } out.write(ip_buf, 0, pkg_len); } out.close(); } // 注意: 代码里省略了很多 try catch.二. 完整代码vpn-client-android这是一个完整的安卓项目
2020年06月16日
1,775 阅读
0 评论
0 点赞
2020-05-03
waifu2x-caffe二次元图片降噪
Waifu2x caffe汉化版是一款新式的专业图片降噪软件,开发时有针对性地考虑了二次元图片,因此对动画截图、CG动画图片之类的降噪效果表现尤为出色,强烈推荐动漫爱好者下载。Waifu2x caffe汉化版使用说明:本软件是免安装版,解压后打开waifu2x-caffe.exe即可运行。 1、添加需要处理的图片(允许拖入添加),支持拖入文奸夹批量处理。 2、变换模式设置:1.纯降噪 2.纯放大 3.降噪&放大 4.降噪(自动)&放大,一般选第3个 3、放大倍数可精确到2位小数点 4、全部设置好后点最右的“运行”即可开始处理Waifu×2的菜单很简单,因为功能单一,所以操作起来并不复杂,选择要放大的图片,然后选择转换质量和放大倍数,然后点击运行即可,放大后的图片直接会出现在原有图片的文件夹中。Waifu2x caffe汉化版使用建议: 1、图片转换格式:设置为PNG,图片输出的色深选择16bit,8bit效果会较弱,但转换更快。 2、在转换质量方面:默认选择降噪和放大即可,降噪水平可自行调整,降噪幅度越大锐度越低。 3、在放大比率方面:可以自行选择,转换倍数越大,图片大小也越大,转换时间也需要更久。下载地址:waifu2x-caffe.ziphttp://pan.baidu.com/s/1jHG4lAA 密码:gpo7waifu2x 一个新式的图片放大&降噪算法,或许不少人早已听说过了。据说开发时有针对性地考虑了2次元类图片,因此对动画截图、galgameCG之类的图片效果更佳出众。 单文件http://pan.baidu.com/s/1bplQTjh 官方版http://pan.baidu.com/s/1slLqo7V
2020年05月03日
1,204 阅读
0 评论
1 点赞
2020-03-25
使用python和redis实现分布式锁
业务场景描述:多个业务节点(多台主机运行同一个业务代码),但是只有一个节点真正运行(运行节点),其他都处于等待(备选节点)运行节点一旦异常(服务挂掉,宕机,误操作等),其他备选节点,立刻有一个继续运行之前的运行节点,重启之后,变为备选节点,处于等待节点实现多节点高可用分布式锁具备的功能:资源唯一表示锁续时(锁绝对不能不设置过期时间)锁误操作(改变了不属于自己的锁)-----资源唯一表示,即可解决Redis 挂掉(或者哨兵模式下,主节点挂掉,哨兵发现和选举延迟,或者redis整个服务挂掉),本地服务处理。redis连接挂掉之后重启,锁可能还在,也可能没有了。没有之后,可能其他的备选节点会加锁成功,成为运行节点也就是说:Redis重启之后,之前的运行节点说不一定不是运行节点了。非运行节点,需要把本地的服务都停掉,确保只有一个运行节点在运行主要业务逻辑额外要求:锁具备高可用,易用,其他业务代码侵入小。所以使用修饰器。实现步骤:唯一资源表示:Redis中的key选取某一个服务名称,value选取主机(或本地IP)+ 主进程ID作为标示代码:def redis_distributed_lock(lock_name: str): """ redis分布式锁 :param lock_name: redis中锁的名称 :return: """ def redis_function(func): def wrapper(self, *args, **kwargs): """ High-availability operating mechanism based on redis :return: None """ redis_model = RedisModel() lock_value = socket.gethostname() + "_" + str(threading.get_ident()) # 没有注册上,休息后再尝试注册 while True: try: result = redis_model.set_ex_nx(key=lock_name, value=lock_value, seconds=60) # 执行主体方法 func(*args, **kwargs) # 获取锁的过期时间 ttl = redis_model.ttl(key=lock_name) time.sleep(ttl if ttl > 1 else 1) except Exception as e: self.logger.warning( "Run redis_distributed_lock failed, cause: {}, traceback: {}".format(e, traceback.format_exc())) time.sleep(5) return wrapper return redis_function锁的续时间:锁续时(锁绝对不能不设置过期时间)。锁续时是个持续的操作(while True),尽量不能影响主体业务逻辑操作。我这里的处理是:续时操作,创建一个额外的线程(watch_dog)或者额外线程执行主体业务逻辑函数。续时需要判断一下,Redis中的锁,还是否为本运行节点锁具有的锁。是的话,才进行续时,防止锁误操作。不是的话,本地的服务可能需要都停掉,主进程处于备用状态,防止多节点运行。1、要删除该运行节点下的所有创建的线程,并且不影响主进程继续运行,并处于备用状态,2、如果子线程创建了进程,等等,需要将该节点下的所有进程也删除掉代码:修饰器:redis_distributed_lock#!/usr/bin/env python # -*- coding: UTF-8 -*- """ ================================================= @Project -> File @IDE :PyCharm @Author :Desmond.zhan @Date :2021/12/7 3:07 下午 @Desc :redis分布式锁,运行执行leader节点的服务器运行,其他的阻塞,以达到高可用 通过注解方式,灵活性更强 ================================================== """ import ctypes import inspect import multiprocessing import socket import threading import time import traceback # 自定义Redis Model. from xxxxxx import RedisModel def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") def _async_stop_children_process(): """ 杀死主进程下所有的子进程 :return: """ children_process = multiprocessing.active_children() for process in children_process: process.terminate() def redis_distributed_lock(lock_name: str): """ redis分布式锁 :param lock_name: redis中锁的名称 :return: """ def redis_function(func): def wrapper(self, *args, **kwargs): """ High-availability operating mechanism based on redis :return: None """ redis_model = RedisModel() lock_value = socket.gethostname() + "_" + str(threading.get_ident()) # 没有注册上,休息后再尝试注册 while True: try: result = redis_model.set_ex_nx(key=lock_name, value=lock_value, seconds=60) # 加锁成功后,判断是否该主机+线程用的这个锁,如果是,设置一个超时时间。否则仍旧等待加锁 self.logger.info("Redis set_nx result:{}".format(result)) self.logger.info( "redis_model.get(lock_name) : {}, lock_value:{}".format(redis_model.get(lock_name), lock_value)) # 加锁成功 if result and redis_model.get(lock_name).decode(encoding="utf8") == lock_value: # 获取到redis分布式锁,开启子线程,进行执行目标函数 t_func = threading.Thread(target=func, args=args, kwargs=kwargs) t_func.start() # 启动看门狗,lock续时 redis_model.lock_watchdog_timeout(key=lock_name, value=lock_value) # 停止函数执行 _async_raise(tid=t_func.ident, exctype=SystemExit) _async_stop_children_process() # 获取锁的过期时间 ttl = redis_model.ttl(key=lock_name) time.sleep(ttl if ttl > 1 else 1) except Exception as e: self.logger.warning( "Run redis_distributed_lock failed, cause: {}, traceback: {}".format(e, traceback.format_exc())) time.sleep(5) return wrapper return redis_function续时操作:watch_dog def lock_watchdog_timeout(self, key, value, seconds=30): self.logger.info("key:{} lock watch dog threading start work ".format(self.get_key(key))) try: self._lock_extend(key, value, seconds) except Exception as e: self.logger.warning("redis lock lock_watchdog_timeout error, error info :{}".format(e)) def _lock_extend(self, key, value, lifetime): while True: try: self.logger.debug("watch dog extend key time, key:{}".format(self.get_key(key))) # 判断redis中还是否为本进程持有的锁 redis_value = self.redis_client.get(name=self.get_key(key)) if redis_value != value: self.logger.warning( "Watch dog warning, redis lock value is not acquired, will suspend function execution") self.logger.warning("this value:{}, redis value".format(value, redis_value)) # watch dog也没意义了,直接返回吧 return result = self.redis_client.expire(name=self.get_key(key), time=lifetime) self.logger.debug("{} extend result : {}".format(self.get_key(key), str(result))) time.sleep(lifetime // 2) except Exception as e: self.logger.warning( "Run _lock_extend failed, cause: {}, traceback: {}".format(e, traceback.format_exc())) time.sleep(5)另外:如果除主进程之外,其他的某些子进程,备选节点也需要保留,可以在_async_stop_children_process()中根据进程名字,或者进程名字前缀,进行过滤,选择性删除子进程如果是子线程创建子进程,子进程再创建进程,可以在_async_stop_children_process()方法中迭代,发现所有的进程,杀死进程之后,这些子进程下的子线程也就不存在了。由于主进程可能创建子线程,而成为备选节点后,主进程仍旧存活,子线程需要清除掉,所有不能使用signal去处理子进程,这里是调用底层C语言暴露的API,可见参考参考 https://www.jianshu.com/p/957853c659f1
2020年03月25日
1,278 阅读
0 评论
0 点赞
2020-03-21
Redis的大key问题
一. 什么是大key?通常指数据内存使用量非常大的数据,比如set里放了相当多的数据ps:我们用set存储了单个用户的文章点赞数据,有个小伙伴天天无聊就在那给文章点赞,点了几百万,那set里就有了几百万数据,这个可能就是一个大key二. 数据层面的解释--避免大key操作业务方应尽量避免进行大key操作,如 hgetall 一次获取非常大的hash数据,用 hmset 一次设置非常多的value,用 lrange 一次取一个非常大的 list 或非常多的元素,如果客户端需要用到这些操作对应的API,一次操作的返回结果大小必须是在合理可控的范围内,防止导致节点通信超时、网络堵塞等严重后果。备注:大key操作通常可见于集群慢日志,同期会伴随缓存调用的高延迟,甚至节点完全阻塞造成的不可用。参考:根据测试结果,value在超过1KB后性能开始下降,超过10KB后性能下降明显,出现拐点。三. 结构层面的大key问题解释 1.资源使用不均(该大key可能会使用该实例相当多的内存,浪费相当大的Cpu,) 2.带宽使用极大(比如假如我们有个功能展示上面例子中点赞的所有文章,一下查出来全部,肯定会使用非常大的带宽) 3.影响该实例其他key的操作(基于redis的单线程处理机制,大家都在排队,前面的慢,自然影响其他数据的操作) 四. 大key如何发现? bigkeys命令 bigkeys命令以遍历的方式分析Redis实例中的所有Key,并返回整体统计信息与每个数据类型中Top1的大Key redis-rdb-tools 使用redis-rdb-tools离线分析工具来扫描RDB持久化文件,虽然实时性略差,但是完全离线对性能无影响。 Redis 4.0 以后的版本:支持 了 memory 命令查看 key 的大小 预估值,不太准确(采用的是多次抽样分析,预估全部数据的量) 五. 如何解决大key问题? 1.数据结构拆分,比如我们这里有个活动数据,活动有活动商品数据,这俩就进行了拆分,并没有放一起 2.数据分片,比如后面加序号,进行多实例的拆分 六. 大key的删除问题6.1 Redis 4.0以前大key删除4.0 以前 string,list,set,hash 不同数据类型的大 key,删除方式有所不同。一般有两种情况:del 命令删除单个很大的 key 和 del 批量删除 大 key。直接 del 命令粗暴的删大 key 容易造成 redis 线程阻塞。4.0 以前要优雅的删除就是针对不同的类型 写脚本,拆分链表,hash 表,分批删除。6.2 Redis 4.0 以后优雅的删除大 key 主动删除 UNLINK xxxkey unlink 命令是 del 的异步版本,由 Lazyfree 机制实现。Lazyfree 机制的原理是在删除的时候只进行逻辑删除,把 key 释放操作放在 bio (Background I/O)单独的子线程中惰性处理,减少删除大 key 对 redis 主线程的阻塞,有效地避免因删除大key带来的性能问题。unlink 即使在批量删除 大 key 时,也不会对阻塞造成阻塞。 被动删除 被动删除是指 Redis 自身的 key 清除策略,一个 大 key 过期或者被淘汰时,如何被清除,会不会导致阻塞?4.0 以前自动清除是有可能阻塞主线程的。 4.0 以后的版本,被动删除策略是可选的配置参数,允许以 Lazyfree 的方式清除。但是参数默认是关闭的,可配置如下参数开启。 lazyfree-lazy-expire on # 过期惰性删除 lazyfree-lazy-eviction on # 超过最大内存惰性删除 lazyfree-lazy-server-del on # 服务端被动惰性删除
2020年03月21日
640 阅读
0 评论
0 点赞
2020-03-12
台式电脑/笔记本刷bios修改开机logo通用教程
无论是台式机还是笔记本开机的第一屏都是bios内置的, 厂家定制的, 不能直接修改.不喜欢这个开机第一屏怎么办呢, 其实刷写bios就可以替换了刷bios改开机logo也没你想的那么难, 简单来说只需三步提取bios替换logo刷写bios做完这三步其实就可以了, 随意定制自己的开机logo, 你可以刷成华为的, 华硕的, 微星的, 外星人的, 苹果的, 也可以自己p个图上去但是也是需要注意: 刷bios有风险, 失败有可能导致开不了机, 一般来说正常操作是不会失败的但是如果出现意外导致开不了机, 可以使用编程器救回, 如下图这种, 带夹子的, 可以直接夹到bios芯片上, 价格30左右.有了编程器也可以刷路由器或显卡等其他的, 没把握的话可以买个编程器备着CH314A编程器00工具下载所需工具fptw64ChangeLogoUEFITool下载https://www.yun.cn/s/de551a7715944c5f8d1395acb4281e79蓝奏云下载:https://wws.lanzous.com/iZ4k7gutg4f 密码:b9un01 提取bios提取bios的方法有很多种, 可以用编程器提取, 可以在dos环境下提取, 也可以在windows下使用不同的软件提取下面就介绍一种比较简单的方法把工具包里的FPTW64复制到D盘根目录点击搜索按钮输入cmd, 以管理员身份运行依次输入下面命令d: cd fptw64 fptw64 -d bak.bin -bios # bak.bin为备份的bios名字, 可以随意取 等待程序跑完显示Memory Dump Complete FPT Operation Successful.之后可以在fptw64文件夹下bak.bin文件, 这就是你机子的bios备份文件02替换logo使用下载下面两个软件ChangeLogoUEFITool1 ChangeLogo打开ChangeLogo 点击load image选择刚才的备份的bios文件, 点击save logo导出开机图片,这张图片就是开机图片了右键属性点详细信息看这张图片的分辨率和大小,使用ps或其他工具编辑这张图片, 或者新建相同分辨率的图, 保存为png格式或jpg格式, 注意文件大小不能超过原有的图, 否则会图会花屏或者出现其他未知的问题,还有可能导致开不了机在线图片压缩 https://www.yasuotu.com/点击browse选择你刚才编辑好的图片, 点击replace logo替换bios的开机图片, 然后点save image as 保存bios镜像完成后使用该软件打开你刚刚生成好的bios镜像, 点击savelogo看看导出的图片是否是刚刚添加的图片校验是否替换成功了, 成功后到第三步刷写bios很多人到点击replace logo这一步卡住, 我的也会, 这个用不了的话可以使用下面的另一种方法2 UEFITool打开软件UEFITool, 选择刚才备份好的bios镜像bak.bin,Ctrl+F打开搜索按钮,点GUID选项,输入7BB28B99-61BB-11D5-9A5D-0090273FC14D点击下方的搜索结果, 展开折叠, 会看到一个raw section项. 右键点击第二项extract body 导出把他命名为xxx.bmp的文件, 打开这个文件看看是否是开机图片, 如果是, 则我们替换它即可替换开机图片右键点击刚才的raw section项, 选择倒数第二个replace body 选择准备好的图片, 替换选择file--save image file 保存为new.bin的bios镜像文件.使用ChangeLogo打开你刚刚生成好的bios镜像, 点击savelogo看看导出的图片是否是刚刚添加的图片校验是否替换成功了, 成功后到第三步刷写bios03刷写bios把制作好的bios镜像文件new.bin复制到之前D盘的fptw64文件夹下管理员权限打开命令行, 切换到fptw64夹下,输入fptw64 -f new.bin -bios, 执行刷新bios程序等待程序跑完, 重启即可看到替换后的开机画面注: 如果出现意外导致开不了机, 可以搜索编程器刷写bios
2020年03月12日
8,704 阅读
0 评论
1 点赞
2020-02-12
Python性能分析工具Line_profiler
介绍profile和line_profiler两个模块都是性能分析工具。有时候需要找到代码中运行速度较慢处或瓶颈,可以通过这两模块实现,而不再使用time计时。line_profiler模块可以记录每行代码的运行时间和耗时百分比。安装输入以下命令安装即可pip install line_profiler使用方法1 :生成一个Line_profiler类(推荐)简单版本from line_profiler import LineProfiler def do_stuff(numbers): s = sum(numbers) l = [numbers[i] / 43 for i in range(len(numbers))] m = ['hello' + str(numbers[i]) for i in range(len(numbers))] if __name__ == '__main__': number = [1,2,3,4,5,6] p = LineProfiler() p_wrap = p(do_stuff) p_wrap(number) p.print_stats() # 控制台打印相关信息 p.dump_stats('saveName.lprof') # 当前项目根目录下保存文件 输出结果:"D:\Program Files\Anaconda3\envs\tensorflow2.3\python.exe" "C:/Users/admin/Desktop/xxxx/temp.py" Timer unit: 1e-07 s Total time: 1.08e-05 s File: C:/Users/admin/Desktop/GPflowMPC_cui _contract - profile/temp.py Function: do_stuff at line 193 Line # Hits Time Per Hit % Time Line Contents ============================================================== 193 def do_stuff(numbers): 194 1 21.0 21.0 19.4 s = sum(numbers) 195 1 45.0 45.0 41.7 l = [numbers[i] / 43 for i in range(len(numbers))] 196 1 42.0 42.0 38.9 m = ['hello' + str(numbers[i]) for i in range(len(numbers))]多函数调用当你需要调用不止一个函数的时候,就可以使用add_function函数去添加额外需要监控的函数from line_profiler import LineProfiler def second_function(): # just for test i = 5 pass def do_stuff(numbers): s = sum(numbers) l = [numbers[i] / 43 for i in range(len(numbers))] m = ['hello' + str(numbers[i]) for i in range(len(numbers))] for i in range(5): second_function() if __name__ == '__main__': number = [1,2,3,4,5,6] p = LineProfiler() p.add_function(second_function) p_wrap = p(do_stuff) p_wrap(number) p.print_stats() p.dump_stats('saveName.lprof')输出结果"D:\Program Files\Anaconda3\envs\tensorflow2.3\python.exe" "C:/Users/admin/Desktop/xxxx/temp.py" Timer unit: 1e-07 s Total time: 2.4e-06 s File: C:/Users/admin/Desktop/GPflowMPC_cui _contract - profile/temp.py Function: second_function at line 193 Line # Hits Time Per Hit % Time Line Contents ============================================================== 193 def second_function(): 194 # just for test 195 5 14.0 2.8 58.3 i = 5 196 5 10.0 2.0 41.7 pass Total time: 2.44e-05 s File: C:/Users/admin/Desktop/GPflowMPC_cui _contract - profile/temp.py Function: do_stuff at line 198 Line # Hits Time Per Hit % Time Line Contents ============================================================== 198 def do_stuff(numbers): 199 1 22.0 22.0 9.0 s = sum(numbers) 200 1 48.0 48.0 19.7 l = [numbers[i] / 43 for i in range(len(numbers))] 201 1 45.0 45.0 18.4 m = ['hello' + str(numbers[i]) for i in range(len(numbers))] 202 6 32.0 5.3 13.1 for i in range(5): 203 5 97.0 19.4 39.8 second_function()方法2:使用装饰器@profile在需要检测的函数上面添加@profile装饰符号, (此时调包是调用profile 而不是line_profiler)。在命令行中使用kernprof -l -v test.py启动,结束会在窗口打印逐行信息以及生成一个lprof文件。 与方法1 相似。问题在于每次不在使用profile 查看性能时,需要将函数上的装饰类注释掉读取lprof 文件: 进入当前目录后,在命令行中使用python -m line_profiler saveName.lprof # saveName.lprof 读取指定文件资料来源 https://blog.csdn.net/weixin_44613728/article/details/120411325
2020年02月12日
916 阅读
0 评论
0 点赞
1
...
3
4
5
...
12