Shadowsocks简介

Shadowsocks(中文名: 影梭) 是一款开源的安全SOCKS 5代理,它主要用于在大陆翻墙。

原理

与SSH动态代理相似,客户端呈现为SOCKS 5代理服务,客户端与服务器之间采用加密通信。服务器部署于GFW之外,从而实现代理翻墙服务。

特点

  • 使用自行设计的协议加密通信,支持多种加密算法:AES、Blowfish、IDEA、RC4等。除创建TCP连接外无需握手,每次请求只转发1个连接,因此使用起来网速较快,在移动设备上较省电。
  • 通过异步I/O和事件驱动实现,响应速度快。
  • 客户端支持主流操作系统平台:Windows、Linux、OS X、Android、iOS和OpenWrt

shadowsocks-libev简介

网络中普遍采用Python版本的shadowsocks,该版本看似安装简单,却存在如下缺点:

  • 没有Linux操作系统原生安装包(如:RPM和DEB):从Ubuntu 16.04开始,提供shadowsocks安装包。
  • 没有操作系统的服务脚本(如init.d和upstart)。
  • Python程序占用内存较多,运行效率不佳。

shadowsocks-libev是Shadowsocks在嵌入式和低端设备的轻量级实现:

  • 纯C实现,不仅占用内存极小,且运行效率更快。
  • 在几乎所有Linux平台都存在原生安装包,且具有对应平台的服务启动脚本。

下面基于Ubuntu 14.04/16.04介绍它的安装和配置。

安装shadowsocks-libev

客户端和服务端的安装方法相同:

sudo add-apt-repository ppa:max-c-lv/shadowsocks-libev
sudo apt-get update
sudo apt-get install -y shadowsocks-libev

配置shadowsocks-libev服务端

编辑/etc/shadowsocks-libev/config.json:

{
    "server_port": 8388,
    "password": "<共享密码>",
    "timeout": 60,
    "method": "aes-256-cfb"
}
  • server_port为服务端监听端口
  • password为客户端和服务端预设的共享密码,它最好由安全密码生成器生成(如LastPassKeePass),且长度不小于6个字符。
  • timeout为连接超时时间。
  • method为加密算法,aes-256-cfb的安全性较好。

配置完成后,需重启:

sudo service shadowsocks-libev restart

配置shadowsocks-libev客户端

创建/etc/shadowsocks-libev/client.json (文件名可修改):

{
    "server": "<服务端地址>",
    "server_port": "<服务端端口>",
    "local_port": "22357",
    "password": "<共享密码>",
    "method": "aes-256-cfb"
}

Ubuntu 14.04

安装包没有提供系统服务脚本,故须自己创建Upstart脚本/etc/init/ss-local.conf (文件名可修改):

基于Python multiprocessing的Actor模型

虽然基于Gevent的Actor基于Python 3.5异步的Actor都支持并发(concurrent)计算(仅运行于单进程中),但是不支持并行(parallel)计算,即无法利用多核。

Python内置的multiprocessing模块不仅支持并行计算,而且与Gevent接口相似。所以,模仿Gevent的Actor实现multiprocessing的Actor并不困难。

multiprocessing的Actor实现

from multiprocessing import Process, Queue

try:
    from Queue import Empty
except ImportError:
    from queue import Empty


class Actor(Process):
    def __init__(self, receive_timeout=None):
        Process.__init__(self)
        self.inbox = Queue()
        self.receive_timeout = receive_timeout

    def send(self, message):
        self.inbox.put_nowait(message)

    def receive(self, message):
        raise NotImplemented()

    def handle_timeout(self):
        pass

    def run(self):
        self.running = True
        while self.running:
            try:
                message = self.inbox.get(True, self.receive_timeout)
            except Empty:
                self.handle_timeout()
            else:
                self.receive(message)

基于message的扩展

将并行Actor扩展为发布-订阅者模式,基本与Gevent的实现一样。

from message import observable

from actor import Actor


@observable
class Publisher(Actor):
    def __init__(self, subject, receive_timeout=None):
        self.subject = subject
        Actor.__init__(self, receive_timeout)

    def subcribe(self, observer):
        self.sub(self.subject, observer.send)

    def publish(self, message):
        self.pub(self.subject, message)

基于Publisher实现Ping-Pong,与Gevent的实现差异也不大。

基于Python 3.5异步的Actor模型

Python 3.5异步模型

Python 3.5推出了async/await语法,在语法层面简化了异步编程。官方库asyncio是应用async/await的途径。

Ubuntu 16.04默认安装Python 3.5,或者通过pyenv安装它。

异步Actor的实现

基于asyncio,可以实现async actor.

import asyncio


class Actor(object):
    def __init__(self):
        self.inbox = asyncio.Queue()
        
    def send(self, message):
        self.inbox.put_nowait(message)

    async def receive(self, message):
        raise NotImplemented()

    async def run(self):
        self.running = True

        while self.running:
            message = await self.inbox.get()
            await self.receive(message)

上述代码的关键是通过asyncio.Queue异步接收消息,并异步处理接收到的消息。

通过这个类,实现Ping-Pong示例:

import asyncio

from actor import Actor


class Pinger(Actor):
    async def receive(self, message):
        print(message)
        pong.send('ping')
        await asyncio.sleep(3)


class Ponger(Actor):
    async def receive(self, message):
        print(message)
        ping.send('pong')
        await asyncio.sleep(3)


ping = Pinger()
pong = Ponger()

ping.send('start')

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait((ping.run(), pong.run())))
loop.close()

该示例代码中,actor之间同步发送消息(asyncio.Queue.put_nowait),由于运行在单线程上,并不存在竞争。

nvm简介——Debian/Ubuntu中管理多版本Node.js

nvm是管理Node.js版本的工具,它支持在多个Node.js版本间切换。

一、安装

git clone https://github.com/creationix/nvm.git ~/.nvm
cd ~/.nvm
git checkout `git describe --abbrev=0 --tags`

激活nvm

. ~/.nvm/nvm.sh

为了每次登录后自动激活nvm,需将NMV_DIRnvm.sh和补齐加入bash的~/.bashrc(或zsh的~/.zshrc)

export NVM_DIR=~/.nvm
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
[ -r $NVM_DIR/bash_completion ] && . $NVM_DIR/bash_completion

在国内,为了加速下述安装,可在bash的~/.bashrc(或zsh的~/.zshrc)加入:

export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node

二、常用命令

列表可安装的Node.js版本

nvm ls-remote

除了Node.js官方版本,还支持io.js

安装指定版本的Node.js

nvm install 10.16.2

它会自动下载指定版本的Node.js二进制包(不需要编译源码),安装在~/.nvm/versions/node

通常,最好安装最近的长周期版本:

nvm install --lts

卸载指定版本的Node.js

nvm uninstall 10.16.2

设置shell的Node.js版本

nvm use 10.16.2

它将Node.js指定版本的bin路径加入PATH.

还原环境变量PATH

nvm deactivate

迁移npm至新版本的Node.js

nvm install node --reinstall-packages-from=node

nvm install v10.16.2 --reinstall-packages-from=10.16.0

.nvmrc

它存储在工程根目录中,用于记录该工程依赖的Node.js版本

echo 10.16.2 > .nvmrc

进入工程目录(当前目录),运行

pyenv简介——Debian/Ubuntu中管理多版本Python

pyenv是管理Python版本的工具,它支持在多个Python版本间切换。

一、安装

git clone https://github.com/pyenv/pyenv.git ~/.pyenv
cd ~/.pyenv
git checkout `git describe --abbrev=0 --tags`

PYENV_ROOTpyenv init加入bash的~/.bashrc(或zsh的~/.zshrc)

echo 'export PATH=~/.pyenv/bin:$PATH' >> ~/.bashrc
echo 'export PYENV_ROOT=~/.pyenv' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
echo 'export PYTHON_BUILD_MIRROR_URL="http://mirrors.sohu.com/python/"' >> ~/.bashrc

二、常用命令

列表可安装的Python版本

pyenv install -l

除了Python官方版本,还支持

  • anaconda
  • ironpython
  • jython
  • miniconda
  • pypy
  • stackless

安装指定版本的Python

安装过程,实际为下载并编译指定版本的Python源码,故需系统安装:

sudo apt-get install -y build-essential zlib1g-dev libssl-dev libffi-dev

还可选择安装:

sudo apt-get install libsqlite3-dev libbz2-dev liblzma-dev libreadline-dev

然后:

pyenv install 3.6.8
pyenv rehash
  • 源码(如Python-3.6.8.tar.gz)缓存在 .pyenv/cache 目录中,在安装完后可手动删除。
  • Python版本安装在~/.pyenv/versions目录中。

卸载指定版本的Python

pyenv uninstall 3.6.8

设置shell的Python版本

pyenv shell 3.6.8

等同于

扩展Python Gevent的Actor模型

什么是Actor模型?

Actor模型中文版)是一种基于消息传递(message-passing)的并发(concurrent)计算模型。

它与OOP异同:

  • 它推崇“一切皆为Actor”,而OOP推崇“一切皆为Object”
  • 表面上,Actor通过发送消息与其他Actor通信,OOP的Object通过发送消息与其他Object通信。实际上,前者为发送结构化的数据,而后者为调用对方的方法。
  • 它的发送者与已经发送的消息解耦,它允许进行异步通信,从而实现发送者与接收者并发执行。而OOP的方法调用者(发送者)与方法被调用者(接收者)通常顺序执行,而且调用者与被调用者通常具有较强的耦合。
  • 它的消息接收者是通过地址区分的,有时也被称作“邮件地址”。而OOP的Object通过引用(地址)来区分。
  • 它着重消息传递,而OOP着重于类与对象。

Gevent的Actor实现

gevent中文版)是一个基于libev的并发库,它为各种并发和网络相关的任务提供了整洁的API。

Actors中文版)章节已介绍了如何基于Greenlet和 Queue实现

该实现存在的问题:发送者与接收者紧耦合,发送者持有接收者的对象引用。

解决办法

在此基础上,我利用message库将其扩展为发布-订阅者模式。

from gevent.queue import Queue
from gevent import Greenlet
from message import observable


class Actor(Greenlet):
    def __init__(self):
        self.inbox = Queue()
        Greenlet.__init__(self)

    def send(self, message):
        self.inbox.put(message)

    def receive(self, message):
        raise NotImplemented()

    def _run(self):
        self.running = True

        while self.running:
            message = self.inbox.get()
            self.receive(message)


@observable
class Publisher(Actor):
    def __init__(self, subject):
        self.subject = subject
        Actor.__init__(self)

    def subcribe(self, observer):
        self.sub(self.subject, observer.send)

    def publish(self, message):
        self.pub(self.subject, message)

如此,不仅将发送者与接收者解耦,而且支持发送者发送1条消息时,多个接收者接收同1条消息。