LEDE 配置 IPv6 以及公网访问

偶然发现江苏电信宽带已经分配了 IPv6 pd 前缀,一不做二不休搞一下。 基础概念 IPv6 与 v4 不同。v4 时代运营商一般只给用户分配1个公网 ip,然后用户自己的路由器通过 NAT 再给局域网设备分配内网 IP,也就是 192.168.x.x 这种。这种情况下内网设备没有独立的公网 IP,要想从公网访问必须配置路由器端口转发。 随着 v4 资源枯竭,现在运营商默认已经不再分配公网 IP 了。要想正常从外网访问,必须做内网穿透。 IPv6 有无数个地址可供分配,“可以给地球上的每一粒沙子都分配一个 IP 地址”。因此运营商分配的策略也会变化。v4 分配的是一个地址,而 v6 分配的是一个前缀,也就是所谓的 pd,相当于是一整个网段,我们可以自己继续往下分配,从而使得每一个局域网设备都能获得公网 IP 地址。 这里采用的方案是光猫桥接,LEDE 路由拨号。 如果无法访问光猫 很多人用 LEDE 连接后可以上网但是打不开光猫的管理页面。 要求:知道光猫的 IP 且不与 LEDE 在同一网段。 假设光猫接到了路由器的 eth0 口,光猫 IP 是192.168.1.1,进入 LEDE 终端执行下面指令: #eth0是接光猫的网口名称,192.168.1.2随便写(是分配给LEDE WAN的IP),不冲突且位于光猫网段就行。 ifconfig eth0 192.168.1.2 netmask 255.255.255.0 #下面两个是添加防火墙规则允许访问光猫 #192.168.1.1为光猫自身IP iptables -I forwarding_rule -d 192.168.1.1 -j ACCEPT #192.168.1.1为光猫自身IP iptables -t nat -I postrouting_rule -d 192....

October 14, 2019 · Chenhe

OpenWrt/LEDE 搭建 Syncthing p2p 私有文件同步服务

简介 因为最近团队有文件同步的需要,常见的公有云服务要么就是不靠谱要么是速度慢,要么就是太贵:expressionless: 饱受好评的坚果云则是限制流量而且据说有隐性限制。 家里上传有 30M 带宽,足够满足常规的文件同步了。常见的私有云系统有 NextCloud/Syncthing/Resilio(BTSync)。NextCloud 更像是一个私人网盘,属于c/s模式,对中心服务器稳定性要求极高,家里路由器感觉无法担此重任。BTSync 是一个基于 BT 的同步软件,近年来大陆的 BT 情况并不好所以也暂不考虑。最终采用 Syncthing。Syncthing 是一个开源免费的文件同步系统,有多平台支持(官方不支持IOS,有一个第三方的收费客户端)。 Syncthing 是分布式的,不依赖中心服务器,如果节点有公网 IP 那么会走直连同步,否则走中继。Syncthing 有不少免费开放的公共中继节点可惜都不在大陆,速度比较慢。如果非常介意可以搭建一个私有中继服务。 先看看成品图: 安装 需要强调:Syncthing 是不分服务器/客户端的。本文仅把路由器节点作为逻辑上的「服务器」以便保证任何时候都有具有公网 IP 的节点在线以便加速传输。 在 release 页面可以看到各个平台编译好的安装包。由于我使用的是 J1900 软路由,所以选择 linux-64 版本。 # 进入用于保存程序的目录 cd /mnt/sda5/ # 下载程序 wget https://github.com/syncthing/syncthing/releases/download/v1.3.0/syncthing-linux-amd64-v1.3.0.tar.gz # 解压 tar -zxvf syncthing-linux-amd64-v1.3.0.tar.gz # 为了方便整洁改个名字 mv syncthing-linux-amd64-v1.3.0 syncthing # 给予执行权限 chmod +x syncthing/syncthing 其实到此为止我们直接执行 syncthing 就能开启服务了。它默认会在 \$HOME/.config/syncthing 创建配置文件。不过我们干脆一次性配置完再运行也不迟。 # 创建一个软链接,就可以在任何目录下执行了 ln -s /mnt/sda5/syncthing/syncthing /usr/bin/syncthing 开机自启...

October 12, 2019 · Chenhe

考研高数公式😑

每天起床第一句,每天起床第一句 泰勒公式记一记 -。- 泰勒公式 $e^x = 1+x+\frac{x^2}{2!}+…+\frac{x^n}{n!}$ $sinx = x-\frac{x^3}{3!}+…+(-1)^n\frac{x^{2n+1}}{(2n+1)!}$ $cosx = 1-\frac{x^2}{2!}+…+(-1)^n\frac{x^{2n}}{(2n)!}$ $ln(1+x) = x-\frac{x^2}{2}+…+(-1)^{n-1}\frac{x^n}{n}$ ,$-1< x\leqslant 1$ $\frac{1}{1-x} = 1+x+x^2+…+x^n$ ,|x|<1 $\frac{1}{1+x} = 1-x+x^2-…+(-1)^nx^n$ $(1+x)^a = 1+ax+\frac{a(a-1)}{2}x^2+O(x^2)$ $tanx = x+\frac{1}{3}x^3+O(x^3)$ $arcsinx = x+\frac{1}{6}x^3+O(x^3)$ $arctanx = x-\frac{1}{3}x^3+O(x^3)$ 高阶导数 $a^{x^{(n)}} = a^x(lna)^n$ ,$a>0, a\neq 1$ $e^{x^{(n)}} = e^x$...

October 10, 2019 · Chenhe

待定系数法拆项

待定系数法是一个非常简单的拆项方法,但是每次用了几天就忘了:confused: 这次专门记录下来哼:expressionless: $$ \frac{5}{2+3x-x^2} \\ =\frac{5}{(2-x)(1+2x)} \\ =\frac{A}{2-x} + \frac{B}{1+2x} $$ 可以得到 $ 5 \equiv A(1+2x) + B(2-x) $ 为了便捷可以直接分别取 $x=2$, $x=-\frac{1}{2}$ 代入。快速求出 $A=1, B=2$。 即原式 $$ I=\frac{1}{2-x} + \frac{2}{1+2x} $$

October 7, 2019 · Chenhe

华硕路由器 ARP 绑定

何为 ARP 绑定 真想不到被吹爆的华硕路由器居然连 ARP 绑定功能都没有。这里要区别一下,在客户端列表中开启 MAC地址与IP绑定 其实仅仅是 DHCP 绑定,它可以保证每次给相同设备总是分配同一个 IP 地址,但前提是设备必须请求IP! 我们知道路由器内部会维护一个 ARP 表,记录 IP 与 MAC 的关系,每当设备请求 IP 时便会被记录,其超时时间因具体设置而不同。因此当设备长时间不在线(比如关机)时吗,ARP 记录就会失效,从而无法再通过 IP 给此设备发送数据。 有一个典型需求:PC 配置 WOL 网络唤醒,然后路由器设置端口转发,这样就可以在外面远程开机了。因此我们要进行 ARP 绑定,与 DHCP 绑定不同,ARP 绑定相当于把 IP 对应关系写死在表里,无论设备是否在线。 方案 ssh 或 telnet 登录路由器,执行 arp -s [IP] [MAC] 就搞定了。 但是这样每次重启都会失效,我们需要通过自启脚本来手动添加 ARP 项,因此官方固件是不行的,先刷梅林。 cd /jffs/scripts/ # 进入脚本目录 vi services-start # 打开编辑器(你也可以用其他编辑器) 将文件内容改为: #!/bin/sh arp -s [IP] [MAC] exit 0 保存,最后给予执行权限: chmod a+rx /jffs/scripts/* OK! 执行 arp 查看 ARP 表,对应项目如果标识有 [PERM] 就是已经绑定了。

September 28, 2019 · Chenhe

三次方程因式分解

说来惭愧,都快大学毕业的人了还不会三次方程因式分解。今天下决心搞懂,原来并不难。茅塞顿开然后感觉好神奇哈哈😂 大致分为三步: 通过常数项试根记为 a 凑出 (x-a) 项 提取公因式 (x-a),并将剩下的继续分解 直接看例子 $x^3+4x^2+5x+2$ $=(x+1)x^2+(x+1)4x+2(x+1)$ $=(x+1)(x^2+3x+2)$ $=(x+1)^2(x+2)$ 首先常数项 2 因数有 -1, 1, 2, -2,我们选择 -1 代入发现确实是对应方程的根。 因此分解后必有一项是 (x+1),在每项中将其凑出并提取。 将剩下的二次多项式用常规方式分解即可。

September 22, 2019 · Chenhe

Koin in Android: 更简单的依赖注入

Dagger 之殇 如果还不清楚什么是依赖注入,那么请参考之前写的 Dagger2 in Android(一)通俗基础开头部分。如果你不了解 Dagger 倒也无妨,本文会进行一定的对比,但仅针对接触过 Dagger 的同学,否则大可以忽略。 Dagger2 作为著名优秀的依赖注入框架广为流传,何况还是 Android 的亲爸爸 - Google 在维护,因此相信很多人会将其作为 Android 开发的首选 DI 框架。Dagger 从入门到放弃一定是很多很多人必经甚至多次经历的历程:anger: 诚然,Dagger 很强大。但它的学习曲线太过于陡峭,即使好不容易搞清楚了各种注解与概念,也很难适当地运用到项目中。同时对于 Activity 之类重要但却不能我们自己初始化的类 Dagger 明显水土不服。为此,Google 搞了个 .android 扩展库来「简化」使用。我不否认最终确实简化了代码,但是这玩意本身就很难度,学习成本堪称指数级。 除此之外,.android 扩展库对于 ViewModel 依然是严重的水土不服,甚至 Google 官方 Demo 的实现也是一堆问题。 Koin 基础 Koin 是纯 Kotlin 编写的轻量级依赖注入框架,轻量是因为它只使用 Kotlin 的函数解析特性,没有代理,没有代码生成,没有反射!官方声称5分钟快速上手。随着 Kotlin 的推广,Koin 这个后起之秀也获得了越来越多的关注。当然它也提供了 implementation "org.koin: koin-java:1.0.0" 扩展库来支持 java,但本文不会涉及。 不建议新手阅读 Koin 源码。作为 DSL,它大量使用了 Kotlin 的高级特性,例如 inline 函数。相对来说难以理解。 使用 Koin 所需的依赖在官方文档已经说得很明确了。这里因为使用了 AndroidX 库,所以引入 org....

July 5, 2019 · Chenhe

[译] Coroutines on Android(三)实战

本系列文章主要翻译自 medium-AndroidDevelopers. 使用协程解决实际问题 前两章重点研究了协程如何简化代码,在 Android 中提供主线程安全,以及如何避免协程泄露。在此基础上,协程是一个在 Android 中进行后台处理以及以及简化回调的优秀方案。 到目前为止,我们主要关注的是什么是协程以及如何管理它们。在这篇文章中,我们将看看如何使用它们来完成实战任务。协程是一个通用的语言特性,与函数在同一个级别——你可以用它实现任何可以用函数或对象来实现的东西。当然,实际工作中有两种情况是非常适合使用协程解决的: 一次性的请求。一旦得到结果那个这次请求就结束了。 流式请求。它持续地观察数据改变并通知调用者——即使得到结果也会持续执行。 这两种任务都非常适合协程。这篇文章中,我们将深入研究一次性请求,并探索如何在 Android 中用协程实现它们。 一次性请求 一次性请求当被调用时执行,当得到结果时返回并结束。就像普通的函数那样——调用它,执行一些工作,然后返回。由于与函数调用的相似性,它比流式请求更容易理解。 一次性请求当被调用时执行,得到结果时结束。 A one shot request is performed each time it’s called. It stops executing as soon as a result is ready. 举个例子,想想浏览器是如何加载网页的。当你点击这篇文章的链接,浏览器会向服务器发送一个请求来加载页面。一旦页面成功传输到浏览器,便会停止与服务器的通讯——浏览器已经得到了所有它需要的数据。如果服务器修改了文章,除非你刷新网页,否则浏览器不会及时修改。 尽管这缺少流式请求的实时推送特性,但一次性请求还是非常强大。一个应用的许多功能都可以通过一次性请求来实现,比如获取、保存、更新数据。对于排序列表之类的事情,它也是一种很好的模式。 需求:显示一个排序的列表 让我们通过探索如何显示排序列表来研究一次性请求。为了更加具体,让我们构建一个库存管理应用,供商店的员工使用。它可以根据最后一次进货的时间查找商品——他们希望能够对列表进行升序和降序排序。但是商品太多了,排序需要几乎1秒才能完成——所以我们使用协程来避免阻塞主线程! 在这个应用中,所有的商品都存储在一个数据库中,使用了 Room 框架。这是一个很好的用例,因为它不需要涉及网络请求,我们可以专注于一次性请求模式本身,麻雀虽小,五脏俱全。 要实现此功能,你需要将协程引入 ViewModel, Repository 以及 Dao。让我们逐个看看怎么与协程进行结合。 class ProductsViewModel(val productsRepository: ProductsRepository): ViewModel() { private val _sortedProducts = MutableLiveData<List<ProductListing>>() val sortedProducts: LiveData<List<ProductListing>> = _sortedProducts /** * 当用户点击排序按钮时调用这些函数。 */ fun onSortAscending() = sortPricesBy(ascending = true) fun onSortDescending() = sortPricesBy(ascending = false) private fun sortPricesBy(ascending: Boolean) { viewModelScope....

July 2, 2019 · Chenhe

[译] Coroutines on Android(二)起步

本系列文章主要翻译自 medium-AndroidDevelopers. 本篇将开始整合协程与 Android,探索如何启动并跟踪协程,以便适配 UI 生命周期。 为何跟踪协程 在第一篇中,我们探索了协程能解决的问题。总结一下,协程是解决这两个问题的优秀方案: 在主线程运行长时间任务导致阻塞。 从主线程上安全地调用一切 suspend 函数。也即主线程安全(Main-safety) 为了解决这些问题,协程通过给常规函数添加 suspend 与 resume 操作,使得协程被挂起时在单独线程执行,主线程可以继续执行其他工作。 但是,协程本身不能跟踪正在执行的工作。协程本身很轻量,你完全可以同时启动大量的协程,甚至成百上千个。 如果要手动编写代码跟踪这几千个协程的进度将非常困难。也许能够追踪他们,确保他们完成或者取消,但这非常枯燥且容易出错。稍有不注意,就会失去对协程的跟踪,也就是协程泄露。 协程泄露就像内存泄露,但是更严重。如果协程泄露,除了占用内存,还会占用 CPU、硬盘甚至启动网络请求。 泄露的协程会浪费内存、CPU、硬盘、网络,而这些都是不需要的。 A leaked coroutine can waste memory, CPU, disk, or even launch a network request that’s not needed. 为了帮助减少协程泄露,Kotlin 介绍了 结构化并发。结构化并发是协程特性与最佳实践的结合,帮助你保持对所有协程的追踪。 在 Android,我们可以利用结构化并发完成三件事: 当不再需要时取消任务。 对运行中的任务保持追踪。 捕获协程中的异常。 让我们深入研究每一个,看看结构化并发如何帮助我们确保始终跟踪所有协程。 使用 scopes 取消任务 在 Kotlin,协程必须在一个叫做 CoroutineScope 内执行。CoroutineScope 保持了对所有协程的跟踪,尽管被挂起也是这样。不像之前我们讨论的 Dispatchers,Scope 实际上不执行协程,只是确保你不会跟丢或忘记它们。 为了保证所有协程都被跟踪,Kotlin 不允许在没有 CoroutineScope 的情况下启动协程。Scope 能够启动具备我们上一节讨论的挂起与恢复能力的协程。...

July 2, 2019 · Chenhe

[译] Coroutines on Android(一)背景知识

本系列文章主要翻译自 medium-AndroidDevelopers. 本系列文章主要关注 Kotlin Coroutine(协程) 是如何工作的,以及如何解决实际的 Android 问题。但是相对来说不会过于深入底层,更偏向于应用。 协程解决了什么? Kotlin 协程提供了一个全新的,更加简单地方式来实现异步。协程在 Kotlin 1.3 中正式发布,API 已经稳定,可以用于生产环境。事实上,协程的概念始终存在,最早是 Simula 语言在1967年探索了协程的使用。 在过去的几年,协程正逐步流行开来,众多的语言,例如 js, c#, python, ruby, go 都有所支持。Kotlin 协程基于这些基础,可以用于构建大型应用程序。 在 Android 上,协程可以优雅地解决下面两个问题: 在主线程运行长时间任务导致阻塞。 从主线程上安全地调用一切 suspend 函数。也即主线程安全(Main-safety) 主线程安全指的是:调用者不必关心这个函数应当在那个线程(调度器)调用,总能“同步”取得正确的返回值且不会阻塞。 下面从这两个角度入手,深入看看协程任何高效整洁地解决这些问题。 长时间运行的任务 调用 API 等行为会涉及到网络请求。读取数据库或加载配置文件涉及到文件读写。这类工作就是所谓的长时间任务,因为相对来说他们花费的时间很长,应用必须停下来等待他们。 在 Android 每个应用都有一个主线程来处理 UI 与交互。如果在这个线程执行了太繁重的工作,应用就会变卡,导致非常糟糕的用户体验。任何长时间运行的任务都不应该阻塞主线程,这样应用才能流畅运行,避免掉帧或未响应的出现。 为了在子线程执行网络请求,最常见的模式是使用回调(Callback)。回调提供了一个引用,它可以在在未来的某个时间通知代码继续运行,使用回调,代码可能是这样的: class ViewModel: ViewModel() { fun fetchDocs() { get("developer.android.com") { result -> show(result) } } } 尽管 get 函数在主线程被调用,但他会在另一个线程执行网络请求。然后一旦得到相应,回调函数就会在主线程执行。这是一个很棒的模式来出来长时间运行的任务。Retorfit 就是一个非常著名的网络请求库帮助你完成这些工作。 使用协程来解决 协程可以大幅简化上面的代码,现在我们用协程来重写上面的功能:...

July 1, 2019 · Chenhe