且行善举,莫问前程。

0%

2016年07月03日更新

  • 添加了daemon
  • 添加了colored logger
  • 优化了启动方式
  • 整理代码
  • 可选使用dnspod token进行授权验证

使用第三方的DDNS服务感觉总是不是太稳定,所以就利用DNSPOD的API编写了一个DDNS的Server。目前依然在开发当中,已经实现了动态域名的功能,接下来是添加更多的功能,使之更加稳定和易用。接下来就是要开始按照计划进行迭代。如果有兴趣一起开发的朋友可以邮箱联系我。

系统环境

ubuntu14.04 Desktop x64

编译nginx

apt-get安装的nginx并不支持websocket,需要添加nginx-push-stream-module模块,所以我们要重新编译nginx。

编译参考模块给出的 参考地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
git clone https://github.com/wandenberg/nginx-push-stream-module.git
# download nginx latest
wget http://nginx.org/download/nginx-1.9.10.tar.gz

# unpack, configure and build
tar zxvf nginx-1.9.10.tar.gz
cd nginx-1.9.10

# add Openssl model,generate Makefile
./configure --add-module=../nginx-push-stream-module --with-http_ssl_module

# if the HTTP rewrite module requires the PCRE library.
# sudo apt-get install libpcre3 libpcre3-dev
# sudo apt-get install openssl libssl-dev

make & sudo make install

更多config配置,使用./config –help默认安装在/usr/local/nginx下

配置websocket

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
# add the push_stream_shared_memory_size to your http context
http {
push_stream_shared_memory_size 32M;

# define publisher and subscriber endpoints in your server context
server {
location /channels-stats {
# activate channels statistics mode for this location
push_stream_channels_statistics;

# query string based channel id
push_stream_channels_path $arg_id;
}

location /pub {
# activate publisher (admin) mode for this location
push_stream_publisher admin;

# query string based channel id
push_stream_channels_path $arg_id;
}

location ~ /sub/(.*) {
# activate subscriber (streaming) mode for this location
push_stream_subscriber;

# positional channel path
push_stream_channels_path $1;
}
}
}

配置一个publisher,配置一个subscriber,以id区分每一个channel也可以直接nginx加载misc/nginx.conf

测试

推荐使用curl直接测试,也可以选择使用iocat测试,需要安装node.js以及npm

1
2
3
4
5
6
7
8
9
10
npm install iocat -g

# WebSocket Client
iocat ws://127.0.0.1:80/sub/1

# WebSocket Server
iocat -l -p 80

# or curl
curl -s -v -X POST 'http://127.0.0.1/pub?id=1' -d 'Hello World!'

因为有个国外的服务器搭了ss的服务,在电脑上使用比较方便.我自己本身有个可用的翻墙host,所以更青睐使用host直接上谷歌,并且github也可以加速.手机并不能使用ss,pad越狱之后才安装了ss的软件.也用过Privoxy将socks转成http,手机经常的切换代理也是很繁琐.

然后有现在解决办法,搭建了dns服务器.

dns服务器搭建在raspberry pi上,系统烧录的是debian系统.使用的dnsmasq软件,修改dns配置,配置翻墙host,修改dns服务器.

安装dnsmasq

1
sudo apt-get install dnsmasq

修改配置文件

1
sudo vi /etc/dnsmasq.conf

修改为

1
2
3
4
5
6
domain=raspberry.local
resolv-file=/etc/resolv.dnsmasq
min-port=4096
server=8.8.8.8
server=8.8.4.4
cache-size=10000

配置host

在/etc/dnsmasq.d/目录下创建gfw.conf,分析hosts文件结构

1
2
3
4
64.233.162.83    0.docs.google.com
64.233.162.83 0.drive.google.com
64.233.162.83 1.docs.google.com
64.233.162.83 1.drive.google.com

dnsmasq配置文件格式

1
2
3
4
address=/0.docs.google.com/64.233.162.83
address=/0.drive.google.com/64.233.162.83
address=/1.docs.google.com/64.233.162.83
address=/1.drive.google.com/64.233.162.83

批量处理hosts文件

1
awk -F ' ' '{print "address=/"$2"/"$1}' /etc/hosts

重启服务,修改dns到树莓派的ip

1
service dnsmasq restart

该篇文章对python内置函数,主要是元编程涉及到的类进行汇总.

__new__和__init__

因为使用markdown,__会被识别为加粗,标题可以使用\_\_来进行转义.或者使用``. `

eg.

1
2
3
4
5
6
7
8
class A(object):
def __init__(self):
print "init"
def __new__(cls,*args, **kwargs):
print "new %s"%cls
return object.__new__(cls, *args, **kwargs)

A()

output:

1
2
new <class '__main__.A'>
init

解释

1
2
3
4
5
继承object的类才有__new__
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行

__repr__

eg.

1
2
3
4
5
6
7
8
9
class A:
def __repr__(self):
return "repr"

def __str__(self):
return "str"

print str(A())
print repr(A())

output:

1
2
str
repr

解释

1
一般类的实现str将被转化为适于人阅读的模式,而repr更适于解释器读取.

__call__

eg.

1
2
3
4
5
6
7
8
9
class A:
def main(self, content):
return content

def __call__(self, content):
return self.main(content)

a = A()
print a('main')

output:

1
main

因为看lilac的源码,看到了带有颜色的logging模块,想到自己曾经在wordpress上写的一片文章《printf有趣的\033》,所以一并可以把文章迁移过来。

shell终端中

1
echo '\033[44;37;5m hello world\033[0m'

会打印出蓝底白字的hell world,这一效果在C中同样可以。

1
2
3
4
5
int main(int argc,char **argv)
{
printf("\033[44;37;5m hello world\033[0m");
return 0;
}

代码解析

1
2
3
4
5
\033     [1;     33;     1m;     xxxx     \033[0m

| | | | | |

开始 背景色 字体色 设置粗体 字符串 结束

其他参数

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
编码    颜色/动作  (m字符前使用)
0       重新设置属性到缺省设置
1       设置粗体
2       设置一半亮度(模拟彩色显示器的颜色)
4       设置下划线(模拟彩色显示器的颜色)
5       设置闪烁
7       设置反向图象
22      设置一般密度
24      关闭下划线
25      关闭闪烁
27      关闭反向图象
30      设置黑色前景
31      设置红色前景
32      设置绿色前景
33      设置棕色前景
34      设置蓝色前景
35      设置紫色前景
36      设置青色前景
37      设置白色前景
38      在缺省的前景颜色上设置下划线
39      在缺省的前景颜色上关闭下划线
40      设置黑色背景
41      设置红色背景
42      设置绿色背景
43      设置棕色背景
44      设置蓝色背景
45      设置紫色背景
46      设置青色背景
47      设置白色背景
49      设置缺省黑色背景

以及其他有趣代码

1
2
3
4
5
6
7
\033[2J          清除屏幕
\033[0q          关闭所有的键盘指示灯
\033[1q          设置“滚动锁定”指示灯 (Scroll Lock)
\033[2q          设置“数值锁定”指示灯 (Num Lock)
\033[3q          设置“大写锁定”指示灯 (Caps Lock)
\033[15:40H     把关闭移动到第15行,40列
\007              发蜂鸣生beep

所以Python中可以这样做一个染色类。

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
class Color(object):
colors = {
'black': 30,
'red': 31,
'green': 32,
'yellow': 33,
'blue': 34,
'magenta': 35,
'cyan': 36,
'white': 37,
'bgred': 41,
'bggrey': 100
}

prefix = '\033['

suffix = '\033[0m'

def __call__(self, text, color):
return self.colored(text, color)

def colored(self, text, color=None):
if color not in self.colors:
color = 'white'

clr = self.colors[color]
return (self.prefix+'%dm%s'+self.suffix) % (clr, text)

colored = Color()

supervisor是python开发的一个守护进程,也是进程管理利器。接触他之后便开始使用它管理服务器上的启动的应用,直到学习Docker之后。

Supervisor官网里面有详细的使用文档

安装

不建议使用pip或者easy_install安装,如果是ubuntu系统建议使用apt-get,以免升级python版本后出现依赖问题。

1
sudo apt-get install supervisor

初始化配置文件

如果使用dpkg安装,则需要初始化配置文件,配置文件在/etc/supervisord/目录下面覆盖掉即可。

1
echo_supervisord_conf > /etc/supervisord.conf

或者指定配置文件

1
supervisord -c supervisord.conf

启动supervisor

1
sudo service supervisord start

开启web管理

修改配置文件,删掉[inet_http_server]配置的注释重启服务,为了安全起见加上密码。

展示一个配置文件

1
2
3
4
5
6
7
8
[program:osu_splider]
command=/home/pi/osu_tool/osu_tool/bin/python /home/pi/osu_tool/osu_splider.py
directory=/home/pi/osu_tool
numprocess=1
autostart=true
autorestart=true
stdout_logfile = /tmp/osu_splider_stdout.log
stderr_logfile = /tmp/osu_splider_stderr.log
  1. [program:xxx] 冒号后一定不能有空格,不然通过supervisorctl管理任务的时候会出现找不到进程的错误
  2. command 运行的程序以及命令
  3. 不再逐条解释,可以选择工作路径程序的运行用户、权限、umask等,详见文档

管理多台服务器一定是自动化运维,因为只有一台服务器,所以用虚拟机创建了3台Ubuntu-Server,开始选择的VirtualBox,因为NAT网络的缘故,主机无法和虚拟机ping通,但是VMware不同,他会虚拟出一个网卡,和虚拟机联通,这样使用NAT更为方便。用VirtualBox,自建虚拟网卡没成功。

还有个方法就是,一个虚拟机使用桥接,虚拟机连入NAT网络中的其他虚拟机,主机通过桥接的虚拟机SSH反向代理连入其他虚拟机。学习个Ansible搞那么麻烦,直接安装VMware吧。

进入Ansible

在google查的资料上说,Ansible通过ssh协议连接服务器,有验证过程。百台服务器以内使用Ansible效率很好,但是千台以上就不适合了。那就需要saltstack了。

安装

我是在Python虚拟环境下安装。直接 pip install ansible。

创建 /etc/ansible/hosts 文件

1
2
3
172.16.75.130:22
172.16.75.129:22
172.16.75.128:22

如果分组,则

1
2
3
4
5
[vm1]    # 组名
172.16.75.130:22 # 主机:指定
172.16.75.129:22
[vm2]
172.16.75.128:22

如果没有使用公钥,使用密码可以这样

1
2
3
4
[vm]
vm1 ansible_ssh_user=root ansible_ssh_host=172.16.75.130 ansible_ssh_pass="test"
vm2 ansible_ssh_user=root ansible_ssh_host=172.16.75.129 ansible_ssh_pass="test"
vm3 ansible_ssh_user=root ansible_ssh_host=172.16.75.128 ansible_ssh_pass="test"

也可以使用通配符 s[001:003].whnzy.com

简单使用

常用参数

1
2
3
4
5
-u username          指定ssh连接的用户名,即执行后面命令的用户
-i inventory_file 指定所使用的inventory文件的位置,默认为/etc/ansible/hosts
-m module 指定使用的模块,默认为command,shell模块可以使用管道,而command则不可以
-f 10 指定并发数,并发量大的时候,提高该值
--sudo [-k] 当需要root权限执行的化,-k参数用来输入root密码,需要安装sshpass(apt-get)

Instance:

第一次连接就会上传公钥

1
2
ansible -i /etc/ansible/hosts all -m command -a 'who' -u haining
ansible -i /etc/ansible/hosts all -m command -a 'who' -u haining

后记

本地没有用root,想用root取执行总是验证失败,而且需要sudo权限的,-k参数也无任何作用。已配置好 本地hosts,config。可以ssh s001 直接登录了。

百度ip定位的接口

1
http://api.map.baidu.com/location/ip?ak=F454f8a5efe5e577997931cc01de3974&ip=202.198.16.3

正好有百度地图的appkey,上面的ak不是本人的。

后来又有查到新浪的ip地址库。

1
2
http://int.dpool.sina.com.cn/iplookup/iplookup.php
http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=123.123.123.123

还有haoservice的库

1
http://www.haoservice.com/docs/5

因为下载了一份JAVA程序源码,在Ubuntu上全是乱码,我想也是用了GBK编码,所以打算用Python处理下。代码写的乱

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
# coding = utf-8
import os

def convert(root, target_filePath, from_encode='gbk', to_encode='utf-8'):
if os.path.exists(root) and os.path.exists(target_filePath):
if os.path.isabs(root):
list_dir = os.listdir(root)
for l in list_dir:
if os.path.isdir(os.path.join(root, l)):
if not os.path.exists(os.path.join(target_filePath, l)):
os.mkdir(os.path.join(target_filePath, l))
convert(os.path.join(root, l), os.path.join(target_filePath, l), from_encode, to_encode)
else:
with open(os.path.join(target_filePath, l), 'w') as f:
for i in open(os.path.join(root, l), 'r'):
f.write(i.decode(from_encode).encode(to_encode))
else:
file_pteh = os.path.join(os.getcwd(), root)
convert(file_pteh, target_filePath, from_encode, to_encode)
else:
print 'fuck!'

root = '/home/haining/bbs'
tar = '/home/haining/tmp'
convert(root, tar)

可以实现将一个目录下的所有文件,转换成指定编码,并且保证目录结构.