Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

Shadowsocks 服务器搭建

13 September 2019 at 11:52

基本上算作官网文档的补充,官网很多东西散落在各个角落,不太好找,本文稍微归纳了一下。

技术发展日新月异,随着时间的流逝文中的一些东西可能会过时,请注意更新时间。

最后修改:2019–08–08。

目前 shadowsocks 中还在不断更新的只有 shadowsocks-libev,本文主要介绍这个。

首先你要有台用于搭建 ss 的服务器。另外本教程适合用户个人使用,如果想建站,请自行查阅其他资料。

shadowsocks-libev

ubuntu 的安装很简单,一条命令即可,不过貌似对 Ubuntu 版本有要求
sudo apt install shadowsocks-libev
安装的可能不是最新版,最新版请手动编译

Centos 7安装

按官网说明安装软件,建议采用手动方法,原因一是能保证用的是最新版,二是出了问题容易上网搜索解决。
Installation

不过官网上写得有些混乱,如果看不懂的话直接无脑进行如下操作即可:

yum install epel-release -y
yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y

git clone https://github.com/shadowsocks/shadowsocks-libev.git
cd shadowsocks-libev
git submodule update --init --recursive

./autogen.sh && ./configure && make
sudo make install

接下来需要将配置文件拷贝到常用路径
添加配置文件:

cp ./rpm/SOURCES/etc/init.d/shadowsocks-libev /etc/init.d/shadowsocks-libev
cp ./debian/config.json /etc/shadowsocks-libev/config.json
chmod +x /etc/init.d/shadowsocks-libev

单用户配置

编辑配置文件

vim /etc/shadowsocks-libev/config.json

修改里面的配置,这里给个 demo,具体每个参数什么意思在官网了解吧:

{
"server":["[::0]","0.0.0.0"],
"server_port":8388,
"local_port":1080,
"password":"barfoo!",
"timeout":60,
"method":"chacha20-ietf-poly1305"
}

该配置同时支持 Ipv6 和 Ipv4,并采用 ss3.0 支持的 AEAD 加密方式。
接下来我们要修改 /etc/init.d/shadowsocks-libev,由于历史原因这里面有点问题。
把文件中的DAEMON=/usr/bin/ss-server改成DAEMON=/usr/local/bin/ss-server
修改完成后修改文件权限

chmod 755 /etc/init.d/shadowsocks-libev

启动 shadowsocks-libev

/etc/init.d/shadowsocks-libev start

多用户配置

多用户配置有多种方法,官方推荐通过给每个用户一个配置文件,启动多个ss-server实现。
还有种方法如下,通过启动ss-manager实现
多用户配置文件与单用户不同,我们配置文件目录创建一个ss_manager.json

{
"server": ["[::0]","0.0.0.0"],
"local_port": 1080, # 本地端口,自行设定
"timeout": 600, # 超时毫秒数
"method": "chacha20-ietf-poly1305",
"port_password": {
"8388": "barfoo1", # 端口号与密码
"8389": "barfoo2"
}
}

设置开机启动

单用户很简单

chkconfig --add shadowsocks 
service shadowsocks start

若是针对多用户情况,需要手写开机启动脚本,方法如下:
应在/usr/lib/systemd/system下新建一个.service文件,例如ssmanager.service

[Unit]
Description=shadowsocks manager # 服务的描述
After=network.target # 该服务跟在哪个服务后启动

[Service]
Type=forking # 启动时的进程行为,forking是以fork形式从父进程创建子进程,子进程创建后父进程退出
ExecStart=/usr/local/bin/ss-manager --manager-address /var/run/shadowsocks-manager.sock -c /etc/shadowsocks/ss_manager.json # 启动服务时执行的命令
PrivateTmp=true # 使用私有临时文件目录

[Install]
WantedBy=multi-user.target # 附挂在multi-user.target下

所有配置文件与脚本都设置完毕,使用systemctl开启服务。

# 更改.service文件后,都要重载守护进程更新systemctl
systemctl daemon-reload
# 启动服务
systemctl start ssmanager.service
# 查看服务状态,若为绿色active(running)则说明服务成功启动
systemctl status ssmanager.service
# 设置服务开机自启动
systemctl enable ssmanager.service
# 还可使用systemctl restart ssmanager.service重启服务,使用systemctl stop ssmanager.service停止服务

开启防火墙白名单

很多人按照教程的配置完后,发现并不能使用,原因是端口被防火墙关闭了。
输入如下代码开启防火墙端口白名单:

vim /etc/firewalld/zones/public.xml

在文件中适当位置添加下面代码:

<port protocol="tcp" port="[server port]"/>
<port protocol="udp" port="[server port]"/>

[server port] 填你的端口号。

重启防火墙

firewall-cmd --complete-reload

客户端

在这里面找适合自己版本的吧
GitHub

开启多进程

shadowsocks-libev 一个进程只能开启一个端口,因此我们要开启多个进程,对应每个进程使用一份相应的配置文件,从而达到多用户使用的目的
配置完多份配置文件后w在 /etc/init.d/shadowsocks 相应位置添加如下代码,一下代码仅供参考,读者可根据实际需求修改,这些代码的意思都很简单。

# 配置文件位置
CONF1=/etc/shadowsocks-libev/config1.json

# 检测配置文件是否存在
if [ ! -f $CONF1 ] ; then
echo "The configuration file1 cannot be found!"
exit 0
fi

# 定位到 pid 文件
PID1=/var/run/$NAME/pid1

# 开启进程
daemon $DAEMON -c $CONF1 -f $PID1

# 杀死进程
killproc -p ${PID1}

# 移除 pid 文件
rm -f ${PID1}

在原来的脚本里有跟上面代码极其相似的地方(数字1没有),把上面的6段代码插入到原来脚本中对应相似的代码后面即可。

Python 与 C++ 数据传输

13 September 2019 at 11:31

因毕设需要,需从 python 将图像数据传给 C++,接收 C++ 处理好后的图像。

新建 C++ 文件接收从 Python传来的数据

#include <opencv2/opencv.hpp>

cv::BackgroundSubtractorMOG2 mog(100, 16, false);

extern "C" void getfg(int rows, int cols, unsigned char* imgData,
unsigned char *fgD) {
cv::Mat img(rows, cols, CV_8UC3, (void *) imgData);
cv::Mat fg(rows, cols, CV_8UC1, fgD);
mog(img, fg);
}

extern "C" void getbg(int rows, int cols, unsigned char *bgD) {
cv::Mat bg = cv::Mat(rows, cols, CV_8UC3, bgD);
mog.getBackgroundImage(bg);
}

所有与 python 交互的 API 必须在 extern "C"中,如果交互 API 过多,上述代码也可以写成如下形式

#include <opencv2/opencv.hpp>

cv::BackgroundSubtractorMOG2 mog(100, 16, false);

extern "C"{
void getfg(int rows, int cols, unsigned char* imgData,
unsigned char *fgD) {
cv::Mat img(rows, cols, CV_8UC3, (void *) imgData);
cv::Mat fg(rows, cols, CV_8UC1, fgD);
mog(img, fg);
}

void getbg(int rows, int cols, unsigned char *bgD) {
cv::Mat bg = cv::Mat(rows, cols, CV_8UC3, bgD);
mog.getBackgroundImage(bg);
}
}

图像数据通过 unsigned char *data 传输进来,通过Mat image(h,w,CV_8UC3,data)转换成C++ OpenCV可识别数据,如果是灰度图,则是CV_8UC1,数据通过指针链接,在C++中是直接修改存在内存中的数据,无需传回。
之后将 C++ 编译成动态链接库,CmakeLists设置如下

add_library(prj SHARED
main.cpp
main.h libmain.cpp)

target_link_libraries(prj ${OpenCV_LIBS})

与C++交互的文件设置如下

import ctypes
# 链接动态库
libmog = ctypes.cdll.LoadLibrary('path/to/libmain.so')

def getfg(img):
(rows, cols) = (img.shape[0], img.shape[1])
res = np.zeros(dtype=np.uint8, shape=(rows, cols))
libmain.getfg(img.shape[0], img.shape[1],
img.ctypes.data_as(ctypes.c_char_p),
res.ctypes.data_as(ctypes.c_char_p)
return res


def getbg(img):
(rows, cols) = (img.shape[0], img.shape[1])
res = np.zeros(dtype=np.uint8, shape=(rows, cols, 3))
libmain.getbg(rows, cols, res.ctypes.data_as(ctypes.c_char_p))
return res

对于需要指针传输的数据,需要用ctypes.data_as(ctypes.c_char_p)将其转换成C++可读取的数据形式

参考文章
stackoverflow

❌
❌