方案设计

主要问题

任何协议,任何IP都有可能被封.

CDN技术


简单来说CDN服务器代理了我们的访问原服务器的流量. 由于CDN服务器具有众多的IP, 而且更容易伪装成网页访问, 因此用来分发请求可以减少被封的可能.

请求<->CDN集群<->服务器

解决方案

websocket代理

由于CDN服务的特殊性, 必须伪装成正常的网页访问, 所以必须使用websocket代理.

宝塔linux面板

简化安装过程,尤其是安装证书那一块. 由于ssl证书的安装比较繁琐, 用caddy的时候也出现了问题.

安装

wget -O install.sh http://download.bt.cn/install/install-ubuntu.sh && sudo bash install.sh

查看端口占用

ss -lntpd 
netstat -tnlp 
lsof -i tcp:22
fuser 

默认的安装方式会出错,改用用DNS安装ssl证书.

开启反向代理,把这个网站做的更像一回事.

再站点的配置页面修改nginx的配置文件.

1
2
3
4
5
6
7
8
9
location /ray 
{
proxy_pass http://127.0.0.1:10000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
}

V2ray

现在网上的垃圾太多了, 搜索一个V2ray的配置好累~

  • Server

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    {
    "log": {
    "access": "",
    "error": "",
    "loglevel": "debug"
    },
    "inbounds": [
    {
    "tag": "vmess-in",
    "port": 10000,
    "listen": null,
    "protocol": "vmess",
    "sniffing": null,
    "settings": {
    "auth": null,
    "udp": false,
    "ip": null,
    "clients": [
    {
    "id": "*",
    "alterId": 64,
    "email": "t@t.tt",
    "security": null
    }
    ]
    },
    "streamSettings": {
    "network": "ws",
    "security": "",
    "tlsSettings": {
    "allowInsecure": true,
    "serverName": null
    },
    "tcpSettings": null,
    "kcpSettings": null,
    "wsSettings": {
    "connectionReuse": true,
    "path": "/ray",
    "headers": null
    },
    "httpSettings": null,
    "quicSettings": null
    }
    }
    ],
    "outbounds": [
    {
    "protocol": "freedom",
    "settings": { },
    "tag": "direct"
    },
    {
    "protocol": "blackhole",
    "settings": { },
    "tag": "blocked"
    }
    ],
    "routing": {
    "domainStrategy": "AsIs",
    "rules": [
    {
    "type": "field",
    "inboundTag": [
    "vmess-in"
    ],
    "outboundTag": "direct"
    }
    ]
    }
    }
  • Client

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    {
    "log": {
    "loglevel": "debug"
    },
    "inbounds": [
    {
    "port": 10086,
    "listen": "0.0.0.0",
    "tag": "socks-in",
    "protocol": "socks",
    "settings": {
    "auth": "noauth",
    "udp": false
    }
    }
    ],
    "outbounds": [
    {
    "mux": {
    "concurrency": 32,
    "enabled": true
    },
    "protocol": "vmess",
    "settings": {
    "vnext": [
    {
    "users": [
    {
    //注:填写uuid
    "id": "UUID",
    "alterId": 64,
    "security": "auto"
    }
    ],
    //注:填写域名、端口
    "address": "domain.Name",
    "port": 1234
    }
    ]
    },
    "streamSettings": {
    "tlsSettings": {
    "allowInsecure": false
    },
    "wsSettings": {
    "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.4489.62 Safari/537.36",
    //注:填写对应头部
    "Host": "HOST",
    "Accept-Encoding": "gzip",
    "Pragma": "no-cache"
    },
    //注:ws路径
    "path": "/PATH/"
    },
    "network": "ws",
    "security": "tls"
    },
    "tag": "proxy"
    },
    {
    "protocol": "blackhole",
    "settings": {},
    "tag": "blocked"
    },
    {
    "protocol": "freedom",
    "settings": {},
    "tag": "dicert"
    }
    ],
    "routing": {
    //注:全域名规则匹配
    "domainStrategy": "AsIs",
    "rules": [
    {
    "type": "field",
    "domain": [
    //注:填写对应域名和host
    "domain:domain.Name"
    ],
    "outboundTag": "dicert"
    },
    {
    "type": "field",
    "inboundTag": [
    "socks-in",
    "http-in"
    ],
    "outboundTag": "proxy"
    }
    ]
    },
    "other": {}
    }

V2rayN客户端生成的配置文件没有out的规则, 之前一直傻乎乎的以为有默认配置.

路由表

rules 对应一个数组,数组中每个元素是一个规则。对于每一个连接,路由将根据这些规则依次进行判断,当一个规则生效时,即将这个连接转发至它所指定的outboundTag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"routing": {
//注:全域名规则匹配
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"domain": [
//注:填写对应域名和host
"domain:domain.Name"
],
"outboundTag": "dicert"
},
{
"type": "field",
"inboundTag": [
"socks-in",
"http-in"
],
"outboundTag": "proxy"
}
]
}

总结

目前websocket+tls+cdn应该是最好的选择,然而使用cloudflare速度太慢,需要考虑使用国内的CDN服务商.

参考

v2ray + CDN
V2RAY配置WebSocket + TLS + Web
V2ray Templates
V2ray 配置

安卓总览

四大组件、六大布局、五大存储

官方文档

  1. Service
  2. broadcastReceiver
  3. Activity
  4. ContentProvider

Activity的生命周期

编程范式

UI

  1. layout
  2. shape:为组件添加样式

定时器

方法: setRepeating(int type,long startTime,long intervalTime,PendingIntent pi)

type 说明
AlarmManager.ELAPSED_REALTIME 表示闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始),状态值为3
AlarmManager.ELAPSED_REALTIME_WAKEUP 表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间,状态值为2
AlarmManager.RTC 表示闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间,状态值为1;
AlarmManager.RTC_WAKEUP 表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,状态值为0;
AlarmManager.POWER_OFF_WAKEUP 表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一,该状态下闹钟也是用绝对时间,状态值为4;不过本状态好像受SDK版本影响,某些版本并不支持;

时间以毫秒为单位

PendingIntent pi:是闹钟的执行动作,比如发送一个广播、给出提示等等。PendingIntent是Intent的封装类。

1
PendingIntent sender=PendingIntent.getBroadcast(Main.this, 0, intent, 0);

SQLlite

存储方式

主要操作:

  1. getWritableDatabase:创建 or 打开 可读/写的数据库(通过 返回的SQLiteDatabase对象 进行操作)
  2. getReadableDatabase:创建 or 打开 可读的数据库(通过 返回的SQLiteDatabase对象 进行操作)
  3. onCreate(SQLiteDatabase db): 数据库第1次创建时 则会调用.在继承SQLiteOpenHelper类的子类中复写.
  4. onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)数据库升级时自动调用.在继承SQLiteOpenHelper类的子类中复写.
  5. (Cursor) query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit): 查询
  6. (long) insert(String table,String nullColumnHack,ContentValues values)
  7. (int) update(String table, ContentValues values, String whereClause, String[] whereArgs)
  8. (int) delete(String table,String whereClause,String[] whereArgs)
  9. (void) execSQL(String sql):直接运行sql语句

术语

可能一些词语使用的不太恰当,一时也想不出好的词,可能存在冒用.

  • 有效区间: 激活函数导数较大的区域.如果导数很小,那么梯度无法传播,权值得不到调整,因此认为是无效的(sigmoid的有效区域为(-3,3),tanh为(-1,1) 这类曲线的界限比较模糊. Hardtanh,或ReLU这类分段线性的函数则是确定的)
  • 泛化程度:如果较少的数据用来学习,那么泛化能力必然低;反之亦然.类似,训练样本在神经有效区域内的数目,决定了学习的空间.数目越多则泛化程度越高. 用t=有效区域内的样本/样本总数 表示.
  • 宽度: 有效区间长度/2
  • 中心: 有效区间的中心.

前面尝试在激活函数前,通过一系数k使得神经元在训练集中被激活的比例达到t.

在神经网络激活函数前增加一系数k:
$$g(kZ),Z = w x +b$$
假设g为sigmoid.k越大,则其有效区域越小;反之越大.
$$ width=\frac{1}{k
w}, center = -b/w$$
k可以改变有效区域长度,而不改变其中心.

由于系数k直接直接根据激活占比t,只能改变宽度.这样直接固定了神经元的泛化程度,实际上减少了神经元的差异性.

实验

生成的数据主要集中在原点附近,同时引入一点干扰以确认不会过拟合.

网络结构如下:

mid =50
model = nn.Sequential(
    nn.Linear(1,mid),
    nn.Tanh(), # 有效趋于为-1~1,比sigmoid更好判断.
    nn.Linear(mid,1)
)

结果一: center和loss

经过16001轮训练后,我发现其50个神经元的中心移动轨迹如下:

横坐标是中心的位置,纵坐标是迭代的次数,同一颜色是同一神经元.(从下往上看就是一个神经元的中心变化情况)

可以发现0-10和60-100之间出现了2次快速移动的情况.同时观察loss的变化,可以发现在神经元移动的同时,loss也在快速下降:

结果二: center和width

观察中心点和宽度的关系,图左为未训练的关系图,图右为训练后:
初始状态训练后
可以明显观察到,原点附近的神经元宽度更小.

结果三: shift

$$ width=\frac{1}{w}=\frac{center}{-b}=, center = -b/w$$
这表明神经网络可以在原点附近的刻画细致的形状,而远离原点趋于线性表达.因此对原有数据进行shift.
神经元未在0.5附近聚集,且其宽度也较大,因此拟合程度欠佳.

结论

训练神经元可以分为2个阶段,移动和塑形.移动阶段,loss能快速地下降,这也是调整网络形状的黄金时期.而在塑性阶段,由于只改变后面一层网络的权值所以修改幅度有限,loss下降缓慢,趋于收敛.

更小的宽度有利于刻画更加细致的形状.

理想的center-width为 神经元聚集在数据密集的地方,且越密集width越小.

问题

以上讨论说明了数据处理的重要性.最好将其处理的到(0,1). 但是如果真实数据是双峰的呢?

能否提出一种权值初始化的方案, 使得网络一开始就能快速学习?

用正态分布初始化权值,聚集在0.5附近;10001轮以后

分段线性函数(Hardtanh,ReLU等)区别挺大的.移动不明显.