Chemmy's Blog

chengming0916@outlook.com

默认配置

默认安装路径:%AppData%\Roaming\npm
全局缓存路径:%AppData%\Roaming\npm_cache

安装全局包命令: npm install -g <包名>

修改方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 设置全局包安装路径
npm config set prefix "<目标路径>"

# 修改缓存包安装路径
npm config set cache "<目标路径>"

# 查看全局包安装路径
npm config get prefix

# 查看缓存包安装路径
npm config get cache

# 查看所有配置
npm config ls

添加环境变量

1
NODE_PATH="<全局安装包路径>\node_modules\"

npm镜像源地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 官方源
https://registry.npmjs.org

# 淘宝npm镜像
https://registry.npmmirror.com

# 阿里云npm镜像
https://npm.aliyun.com

# 腾讯云npm镜像
https://mirrors.cloud.tencent.com/npm

# 华为云npm镜像
https://mirrors.huaweicloud.com/repository/npm

# 网易npm镜像
https:/mirrors.163.com/npm

修改镜像源

1
2
3
4
5
# 修改镜像源
npm config set registry https://registry.npmmirror.org

# 查看镜像源
npm config get registry

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
sudo vim /etc/sysctl.d/99-sysctl.conf:     #重启后生效
fs.inotify.max_user_watches = 600000
dev.i915.perf_stream_paranoid = 0
vm.swappiness = 1
net.ipv6.conf.all.accept_ra = 2
fs.file-max = 6553560
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.rmem_default = 65536
net.core.wmem_default = 65536
net.core.optmem_max = 10000000
net.core.netdev_max_backlog = 8096
net.core.somaxconn = 8096
net.ipv4.ip_default_ttl = 128
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_ecn = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_fack = 1
net.ipv4.tcp_low_latency = 0
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_frto = 2
net.ipv4.tcp_frto_response = 0
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_max_syn_backlog = 30000
net.ipv4.tcp_max_orphans = 262114
net.ipv4.netfilter.ip_conntrack_max = 204800
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# for high-latency network Google BBR #个人PC不建议开启BBR,对网速不会有提升,还会降低wifi吞吐量;还是等BBR2正式版出了再开启BBR2吧,BBR2对wifi就没有影响了
#net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq_codel
net.ipv4.tcp_congestion_control = cubic
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0
net.ipv6.ip_default_ttl = 128
1
2
3
4
5
sudo vim /etc/security/limits.conf:
* soft nofile 65536
* hard nofile 65536
* soft noproc 65536
* hard noproc 65536

概述

netfilter/iptables 为 Linux 内核级有状态防火墙。支持连接跟踪,包含四种有效状态:ESTABLISHEDINVALIDNEWRELATED


一、安装与检测

  • 检测安装:whereis iptables
  • 安装命令:apt-get install iptables
  • 加载内核模块:modprobe ip_tables

二、规则配置

编辑策略文件:vi /etc/iptables.rules

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
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

# 允许特定IP访问8080
-A INPUT -s 59.109.149.221 -p tcp -m tcp --dport 8080 -j ACCEPT

# 常用业务端口
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 7080 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 7180 -j ACCEPT

# 状态追踪(允许已建立和相关连接)
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Loopback接口(保障本地通信与DNS)
-A OUTPUT -o lo -p all -j ACCEPT
-A INPUT -i lo -p all -j ACCEPT

# SSH连接(端口需与 /etc/ssh/sshd_config 一致)
-A INPUT -p tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp --sport 22 -j ACCEPT

# ICMP控制(允许ping,丢弃时间戳等探测包)
-I INPUT -p icmp --icmp-type echo-request -j ACCEPT
-A INPUT -p ICMP --icmp-type timestamp-request -j DROP
-A INPUT -p ICMP --icmp-type timestamp-reply -j DROP
-A INPUT -p ICMP --icmp-type time-exceeded -j DROP
-A INPUT -p icmp --icmp-type 8 -s 0/0 -j DROP
-A OUTPUT -p ICMP --icmp-type time-exceeded -j DROP

# 默认拒绝策略
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A INPUT -p tcp -m tcp --dport 8080 -j DROP
COMMIT

[!NOTE]
INPUT 为入口,OUTPUT 为出口,REJECT 为禁止。若需完全开放出口,将默认策略改为 -A OUTPUT -j ACCEPT


三、加载与持久化

  • 加载生效:iptables-restore < /etc/iptables.rules
  • 查看规则:iptables -L -n
  • 开机自启配置:
    • 创建软链:ln -s /lib/systemd/system/rc-local.service /etc/systemd/system/
    • 编辑服务:vi /lib/systemd/system/rc-local.service,末尾追加 [Install]
    • 创建脚本:vi /etc/rc.local,写入 iptables-restore < /etc/iptables.rules
    • 赋权:chmod +x /etc/rc.local

四、常用命令速查

4.1 基础管理

1
2
3
4
5
6
7
8
# 查看现有规则
iptables -L -n
# 临时放行所有(防误锁)
iptables -P INPUT ACCEPT
# 清空规则
iptables -F # 清空默认规则
iptables -X # 清空自定义规则
iptables -Z # 计数器归零

4.2 端口与协议

1
2
3
4
5
6
7
# 开放常用端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # SSH
iptables -A INPUT -p tcp --dport 21 -j ACCEPT # FTP
iptables -A INPUT -p tcp --dport 80 -j ACCEPT # HTTP
iptables -A INPUT -p tcp --dport 443 -j ACCEPT # HTTPS
# 允许ping
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT

4.3 策略与黑白名单

1
2
3
4
5
6
7
8
9
# 设置默认策略
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
# 信任内网IP(放行所有TCP)
iptables -A INPUT -p tcp -s 45.96.174.68 -j ACCEPT
# 封停/解封IP
iptables -I INPUT -s ***.***.***.*** -j DROP
iptables -D INPUT -s ***.***.***.*** -j DROP

4.4 保存规则

1
service iptables save

五、核心概念对照

方向 说明
INPUT 入站 目标为本机的数据包
OUTPUT 出站 源为本机的数据包
FORWARD 转发 经本机路由转发的数据包
状态 说明
ESTABLISHED 已建立的连接
NEW 新连接请求
RELATED 与已有连接关联的数据包
INVALID 无法识别或无效的数据包

一、 概述

TDengine 是一款开源、高性能、云原生的时序数据库(Time Series Database, TSDB),专为物联网、车联网、工业互联网、金融、IT 运维监控等场景设计。

  • 官方文档https://docs.taosdata.com/
  • 核心组件(容器内包含):
    • taosd: 数据库核心服务。
    • taosAdapter: 提供 RESTful 和 WebSocket 接口。
    • taosKeeper: 系统监控指标收集。
    • taosExplorer: Web 管理控制台。

二、 单节点部署(快速体验)

1. 使用 Docker Compose 启动

创建 docker-compose.yml 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: '3.9'
services:
tdengine:
image: tdengine/tdengine:3.3.4.3 # 可使用最新稳定版标签
container_name: tdengine
ports:
- '6030:6030' # taosd 核心服务端口
- '6041:6041' # taosAdapter Restful API
- '6043:6043' # taosKeeper 指标监控
- '6060:6060' # taosExplorer Web控制台
- '6044-6049:6044-6049' # 第三方数据接入
- '6044-6045:6044-6045/udp' # UDP 接入
volumes:
- './data:/var/lib/taos' # 数据持久化
- './log:/var/log/taos' # 日志持久化

启动服务:docker-compose up -d

2. 连接测试与基本操作
  1. 进入容器
    1
    docker exec -it tdengine bash
  2. 生成测试数据(使用官方工具):
    1
    taosBenchmark -y
    此命令会在 test 数据库下创建一张名为 meters 的超级表,包含 10,000 张子表,每表 10,000 条记录。
  3. 使用 CLI 连接数据库
    1
    taos
    1
    2
    3
    -- 在 taos 提示符下执行
    USE test;
    SELECT COUNT(*) FROM meters;
  4. 修改默认密码
    1
    ALTER USER root PASS 'YourNewPassword';
  5. 使用密码登录
    1
    taos -uroot -pYourNewPassword
  6. 访问 Web 控制台
    浏览器访问 http://<服务器IP>:6060,使用数据库用户名密码登录 taosExplorer 进行可视化管理。

三、 生产集群部署

1. 集群规划

假设使用 3 台服务器,所有节点均部署 TDengine。

服务器 IP 地址 部署服务 对外代理端口 (Nginx)
node0 192.168.4.211 TDengine -
node1 192.168.4.115 TDengine -
node2 192.168.0.37 TDengine, Nginx 16041, 16043, 16060

端口说明:每个 TDengine 容器需开放与单节点相同的端口(6030, 6041, 6043, 6060, 6044-6049)。

2. 部署步骤

(1)所有节点:准备配置文件

1
2
3
4
5
6
7
8
9
10
# 1. 启动临时容器获取默认配置
docker run --rm -it --name=tdengine-temp tdengine/tdengine:3.3.4.3 taos

# 2. 另开终端,拷贝配置
docker cp tdengine-temp:/etc/taos ./conf

# 3. 修改配置中的主机名(替换为当前节点IP)
CURRENT_IP=$(YOUR_NODE_IP) # 请替换为实际IP,如 192.168.4.211
cd conf
sed -i "s/buildkitsandbox/$CURRENT_IP/g" explorer.toml taosadapter.toml taos.cfg taoskeeper.toml

(2)所有节点:配置集群首个节点 (firstEp)
编辑 conf/taos.cfg 文件,所有节点的此配置必须相同

1
2
# 指向规划中第一个启动的节点(例如 node0)
firstEp 192.168.4.211:6030

(3)所有节点:启动 TDengine 服务
创建 docker-compose.yml,使用 host 网络模式以便节点间通信。

1
2
3
4
5
6
7
8
9
10
version: '3.9'
services:
tdengine:
image: tdengine/tdengine:3.3.4.3
container_name: tdengine
network_mode: host # 关键:使用主机网络
volumes:
- './data:/var/lib/taos'
- './log:/var/log/taos'
- './conf:/etc/taos' # 挂载自定义配置

启动:docker-compose up -d

启动顺序建议:先启动 firstEp 指向的节点(node0),再启动其他节点。

3. 集群验证与管理
  1. 查看数据节点
    1
    docker exec -it tdengine taos
    1
    SHOW DNODES;
    输出应显示 3 个 statusready 的节点。
  2. 添加管理节点(Mnode)以实现高可用
    首个启动的 dnode 自动成为 Mnode(管理节点)。为防止单点故障,需添加冗余 Mnode。
    1
    2
    3
    4
    -- 在 dnode 2 (node1) 上创建第二个 Mnode
    CREATE MNODE ON DNODE 2;
    -- 查看 Mnode 状态
    SHOW MNODES;
    输出应显示一个 leader 和一个 follower Mnode。

四、 高可用与负载均衡(Nginx 代理)

node2 上部署 Nginx,对外提供统一的访问入口,实现 taosAdapter (REST API)、taosKeeper (监控) 和 taosExplorer (Web) 的负载均衡。

1. 创建 Nginx 配置文件 (nginx.conf)
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
user root;
worker_processes auto;
events {
use epoll;
worker_connections 1024;
}
http {
access_log off;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

# 1. 代理 taosAdapter (REST API, 6041)
server {
listen 16041;
location / {
proxy_pass http://dbserver;
proxy_read_timeout 600s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}

# 2. 代理 taosKeeper (监控, 6043)
server {
listen 16043;
location / {
proxy_pass http://keeper;
}
}

# 3. 代理 taosExplorer (Web控制台, 6060)
server {
listen 16060;
location / {
proxy_pass http://explorer;
# 处理 CORS 头部(如果前端需要)
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}

# 上游服务器定义
upstream dbserver {
least_conn; # 最少连接负载均衡
server 192.168.4.211:6041 max_fails=0;
server 192.168.4.115:6041 max_fails=0;
server 192.168.0.37:6041 max_fails=0;
}
upstream keeper {
ip_hash; # 保持会话
server 192.168.4.211:6043;
server 192.168.4.115:6043;
server 192.168.0.37:6043;
}
upstream explorer {
ip_hash; # 保持会话
server 192.168.4.211:6060;
server 192.168.4.115:6060;
server 192.168.0.37:6060;
}
}
2. 使用 Docker Compose 启动 Nginx

创建 docker-compose-nginx.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
version: '3.9'
services:
nginx:
restart: always
image: nginx:1.23.1
container_name: nginx-tdengine
ports:
- '16041:16041'
- '16043:16043'
- '16060:16060'
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./nginx-logs:/var/log/nginx

启动:docker-compose -f docker-compose-nginx.yml up -d

3. 验证代理

通过 Nginx 代理访问 REST API:

1
2
3
4
curl -L 'http://192.168.0.37:16041/rest/sql/test' \
-H 'Content-Type: text/plain' \
-H 'Authorization: Basic cm9vdDp0YW9zZGF0YQ==' \ # Base64编码的 root:taosdata
-d 'SELECT * FROM meters LIMIT 1'

应返回包含测试数据的 JSON 响应。

五、 关键注意事项

  1. 版本一致性:集群所有节点必须使用相同版本的 TDengine 镜像。
  2. 网络:集群部署必须使用 host 网络或确保容器间在 6030-6049 端口上能直接通信。
  3. 防火墙:确保服务器防火墙开放相关端口。
  4. 数据持久化:务必挂载 /var/lib/taos 目录以防止数据丢失。
  5. **firstEp**:此配置是集群组建的关键,必须正确且一致。
  6. Mnode:生产环境至少配置 2 个 Mnode 以实现管理层面的高可用。

OpenCV进行RTSP推流

1 概述

将 OpenCV 处理后的图像直接进行 RTSP 推流,支持多种实现方案。


2 测试命令

2.1 推流本地文件

1
gst-launch-1.0 filesrc location=D:\5.mp4 ! decodebin ! videoconvert ! x264enc ! rtspclientsink location=rtsp://127.0.0.1:8554/live

2.2 播放推流内容

1
gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/live ! rtph264depay ! h264parse ! avdec_h264 ! autovideosink

3 方案一:GStreamer推流

3.1 核心代码

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
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <opencv2/opencv.hpp>

#define RTSP_SERVER_URL "rtsp://127.0.0.1:8554/live"
#define CAPTURE_WIDTH 640
#define CAPTURE_HEIGHT 480
#define CAPTURE_FPS 30
#define FRAME_INTERVAL_MS (1000 / CAPTURE_FPS)

int main(int argc, char* argv[])
{
// 初始化GStreamer
gst_init(&argc, &argv);
std::cout << "3e" << std::endl;

// 创建管道
GstElement* pipeline = gst_pipeline_new("rtsp-pipeline");
GstElement* appsrc = gst_element_factory_make("appsrc", "app-source");
GstElement* videoconvert = gst_element_factory_make("videoconvert", "convert");
GstElement* x264enc = gst_element_factory_make("x264enc", "encoder");
GstElement* rtph264pay = gst_element_factory_make("rtph264pay", "payloader");
GstElement* rtspclientsink = gst_element_factory_make("rtspclientsink", "sink");

// 配置appsrc
g_object_set(G_OBJECT(appsrc), "is-live", TRUE, NULL);
g_object_set(G_OBJECT(appsrc), "format", GST_FORMAT_TIME, NULL);
g_object_set(G_OBJECT(appsrc), "caps", gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "BGR",
"width", G_TYPE_INT, CAPTURE_WIDTH,
"height", G_TYPE_INT, CAPTURE_HEIGHT,
"framerate", GST_TYPE_FRACTION, CAPTURE_FPS, 1,
NULL), NULL);

// 添加元素到管道
gst_bin_add_many(GST_BIN(pipeline), appsrc, videoconvert, x264enc, rtph264pay, rtspclientsink, NULL);

// 连接元素
gst_element_link_many(appsrc, videoconvert, x264enc, rtph264pay, rtspclientsink, NULL);

// 配置RTSP目标地址
g_object_set(G_OBJECT(rtspclientsink), "location", RTSP_SERVER_URL, NULL);

// 启动管道
gst_element_set_state(pipeline, GST_STATE_PLAYING);

// 打开摄像头
cv::VideoCapture cap(0);
if (!cap.isOpened()) {
std::cerr << "Error: Unable to open camera." << std::endl;
return -1;
}

// 推流循环
while (true)
{
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
std::cerr << "Warning: Empty frame." << std::endl;
continue;
}

// 打印时间戳(精确到毫秒)
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
auto t = std::chrono::system_clock::to_time_t(now);
auto tp = std::chrono::system_clock::from_time_t(t);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - tp).count();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
std::cout << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X") << "." << ms << std::endl;

// 创建GStreamer缓冲区
GstBuffer* buffer = gst_buffer_new_allocate(NULL, frame.total() * frame.elemSize(), NULL);
GstMapInfo map;
gst_buffer_map(buffer, &map, GST_MAP_WRITE);
memcpy(map.data, frame.data, frame.total() * frame.elemSize());
gst_buffer_unmap(buffer, &map);

// 推送缓冲区
GstFlowReturn ret;
g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
gst_buffer_unref(buffer);

// 控制帧率
g_usleep(FRAME_INTERVAL_MS * 1000);
}

// 清理资源
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);

return 0;
}

3.2 流程说明

步骤 操作
1 初始化 GStreamer
2 创建管道和元素(appsrc → videoconvert → x264enc → rtph264pay → rtspclientsink)
3 配置 appsrc 参数(分辨率、帧率、格式)
4 启动管道
5 循环读取摄像头帧并推送

4 方案二:FFmpeg推流

4.1 头文件

1
2
3
#include "rtspencoder.h"
#include <QCoreApplication>
#include <QDebug>

4.2 类定义

1
2
3
4
5
6
7
8
9
10
RTSPEncoder::RTSPEncoder(const char* rtspUrl, int outputWidth, int outputHeight, QObject* parent)
: QThread(parent), m_rtspUrl(rtspUrl), m_outputWidth(outputWidth), m_outputHeight(outputHeight)
{

}

RTSPEncoder::~RTSPEncoder()
{
cleanup();
}

4.3 初始化

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
int RTSPEncoder::initialize()
{
avformat_network_init();

// 初始化输出上下文
m_outFormatCtx = nullptr;
avformat_alloc_output_context2(&m_outFormatCtx, nullptr, "rtsp", m_rtspUrl.c_str());
if (!m_outFormatCtx)
{
std::cerr << "Error: Failed to allocate output context\n";
return -1;
}

// 查找H264编码器
m_codec = (AVCodec*)avcodec_find_encoder(AV_CODEC_ID_H264);
if (!m_codec) {
std::cerr << "Error: Failed to find H264 encoder\n";
return -1;
}

// 添加视频流
m_outStream = avformat_new_stream(m_outFormatCtx, m_codec);
if (!m_outStream) {
std::cerr << "Error: Failed to create new stream\n";
return -1;
}

// 初始化编码器上下文
m_codecCtx = avcodec_alloc_context3(m_codec);
if (!m_codecCtx) {
std::cerr << "Error: Failed to allocate codec context\n";
return -1;
}
m_codecCtx->codec_id = AV_CODEC_ID_H264;
m_codecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
m_codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
m_codecCtx->width = m_outputWidth;
m_codecCtx->height = m_outputHeight;
m_codecCtx->time_base = { 1, 25 }; // 25fps
m_codecCtx->bit_rate = 700000;
m_codecCtx->gop_size = 10;
m_codecCtx->max_b_frames = 0;
m_codecCtx->flags = AV_CODEC_FLAG_GLOBAL_HEADER | AV_CODEC_FLAG_LOW_DELAY;

// 配置编码器选项
AVDictionary* codecOptions = nullptr;
av_dict_set(&codecOptions, "preset", "ultrafast", 0);
av_dict_set(&codecOptions, "tune", "zerolatency", 0);

// 打开编码器
if (avcodec_open2(m_codecCtx, m_codec, &codecOptions) < 0) {
std::cerr << "Error: Failed to open encoder\n";
return -1;
}

// 复制编码器参数到输出流
avcodec_parameters_from_context(m_outStream->codecpar, m_codecCtx);

// 写入流头部
avformat_write_header(m_outFormatCtx, nullptr);

m_frame.create(m_outputHeight, m_outputWidth, CV_8UC3);
m_frame.setTo(0);
m_frameCount = 0;

m_avFrame = av_frame_alloc();

return 0;
}

4.4 编码与发送

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
void RTSPEncoder::encodeFrameAndSend()
{
while (1)
{
// 阻塞等待新帧
{
std::unique_lock<std::mutex> lock(mtx);

while (!m_isReady) {
m_cv.wait(lock);
}
m_isReady = false;

// 转换颜色空间 BGR → I420
cv::cvtColor(m_frame, m_im420, cv::COLOR_RGB2YUV_I420);

// 配置AVFrame
m_avFrame->data[0] = m_im420.data;
m_avFrame->data[1] = m_avFrame->data[0] + m_codecCtx->width * m_codecCtx->height;
m_avFrame->data[2] = m_avFrame->data[1] + m_codecCtx->width * m_codecCtx->height / 4;
m_avFrame->linesize[0] = m_codecCtx->width;
m_avFrame->linesize[1] = m_codecCtx->width / 2;
m_avFrame->linesize[2] = m_codecCtx->width / 2;
m_avFrame->width = m_codecCtx->width;
m_avFrame->height = m_codecCtx->height;
m_avFrame->format = AV_PIX_FMT_YUV420P;
m_avFrame->pts = m_frameCount++;

// 发送帧到编码器
auto ret = avcodec_send_frame(m_codecCtx, m_avFrame);
if (ret < 0)
{
std::cerr << "Error: Failed to send frame for encoding\n";
return;
}

// 接收编码后的数据包
AVPacket pkt;
av_init_packet(&pkt);
while (ret >= 0)
{
ret = avcodec_receive_packet(m_codecCtx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
std::cout << "Error: Failed to receive encoded packet\n";
continue;
}
pkt.stream_index = m_outStream->index;
av_packet_rescale_ts(&pkt, m_codecCtx->time_base, m_outStream->time_base);
ret = av_interleaved_write_frame(m_outFormatCtx, &pkt);
av_packet_unref(&pkt);

if (ret < 0)
{
std::cout << "Error: Failed to write packet to output stream\n";
continue;
}
}
}
}
}

4.5 添加帧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void RTSPEncoder::AddFrame(cv::Mat& imGBR, int nFrame)
{
if (imGBR.cols != m_outputWidth || imGBR.rows != m_outputHeight)
return;

// 阻塞等待编码
{
std::lock_guard<std::mutex> lock(mtx);
memcpy(m_frame.data, imGBR.data, imGBR.cols * imGBR.rows * 3);
m_frameCount = nFrame;
m_isReady = true;
}
m_cv.notify_one();
}

4.6 资源清理

1
2
3
4
5
6
7
8
9
10
11
12
13
void RTSPEncoder::cleanup()
{
// 写入尾部
av_write_trailer(m_outFormatCtx);

// 释放资源
if(m_codecCtx)
avcodec_free_context(&m_codecCtx);
if(m_avFrame)
av_frame_free(&m_avFrame);
if(m_outFormatCtx)
avformat_free_context(m_outFormatCtx);
}

5 方案三:OpenCV GStreamer后端

5.1 推流代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void push()
{
int codec = cv::VideoWriter::fourcc('H', 'E', 'V', 'C');
m_writer.open(push_str, codec, fps, cv::Size(width, height));

cv::Mat tmp;
while (true)
{
{
std::unique_lock<std::mutex> lk(proc2push_mtx);
proc2push_cv.wait(lk);
tmp = img_push.clone();
}

if (!m_writer.isOpened())
{
int codec = cv::VideoWriter::fourcc('H', 'E', 'V', 'C');
m_writer.open(push_str, codec, fps, cv::Size(width, height));
}

m_writer.write(tmp);
}
}

5.2 优缺点

方案 优点 缺点
GStreamer 灵活性高,延迟低 代码复杂
FFmpeg 功能强大,兼容性好 学习成本高
OpenCV GStreamer 实现简单 延迟较高

6 测试代码

6.1 视频源测试

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
int main1()  
{
// USB摄像头(GStreamer格式)
std::string pipeline = "v4l2src device=/dev/video0 ! image/jpeg,width=1920,height=1080,framerate=30/1 ! nvv4l2decoder mjpeg=1 ! nvvidconv ! appsink";
cv::VideoCapture capture(pipeline, cv::CAP_GSTREAMER);

if (!capture.isOpened())
{
std::cout << "Read video Failed !" << std::endl;
return -1;
}

cv::Mat frame;
cv::namedWindow("video test");

int frame_num = capture.get(cv::CAP_PROP_FRAME_COUNT);
std::cout << "total frame number is: " << frame_num << std::endl;

while(1)
{
capture >> frame;
imshow("video test", frame);
if (cv::waitKey(30) == 'q')
{
break;
}
}

cv::destroyWindow("video test");
capture.release();
return 0;
}

6.2 GStreamer命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 文件推流
gst-launch-1.0 -v filesrc location=D:/1.mp4 ! decodebin ! x264enc ! rtph264pay ! udpsink host=127.0.0.1 port=8554

# RTSP播放
gst-launch-1.0 -v rtspsrc location=rtsp://127.0.0.1:10054/live/Fs4FsmKSR ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! autovideosink

# 测试源
gst-launch-1.0 -v videotestsrc ! video/x-raw, format=BGRx ! autovideosink

# AppSource推流
gst-launch-1.0 -v appsrc name=mysource is-live=true block=true format=GST_FORMAT_TIME \
! videoconvert \
! video/x-raw,format=NV12 \
! nvv4l2h264enc \
! video/x-h264,stream-format=byte-stream \
! h264parse \
! rtspclientsink location=rtsp://localhost:8554/mystream

7 总结

方案 适用场景
GStreamer 低延迟、高性能推流
FFmpeg 复杂编码需求、跨平台
OpenCV GStreamer 简单场景、快速实现

本文档整合了多种SOCKS5代理服务器的搭建方法,包括SS5DanteSquidMicrosocks,旨在为不同需求和场景提供选择。

一、 方案概览与选择

方案 特点 适用场景 复杂度
SS5 经典SOCKS5服务器,功能全面,支持用户认证。 需要稳定、功能完整的SOCKS5代理。 中等
Dante 轻量级、高性能的SOCKS4/5服务器,配置灵活。 对性能和资源占用有要求的生产环境。 中等
Squid 功能强大的HTTP/HTTPS缓存代理,也支持SOCKS。 主要需求为Web缓存,同时需要SOCKS功能。 较高
Microsocks 极致轻量、内存占用极小的SOCKS5服务器。 资源受限的VPS、临时或简单代理需求。

环境建议:CentOS 7.x, Debian 7+, Ubuntu 14.04+。避免使用CentOS 8.x(兼容性问题)。确保服务器防火墙/安全组已开放代理端口。


二、 SS5 搭建方案

SS5是一个功能完整的SOCKS5代理服务器。

1. 安装依赖与源码

1
2
3
4
5
6
7
yum -y install gcc gcc-c++ automake make pam-devel openldap-devel cyrus-sasl-devel openssl openssl-devel
wget http://nchc.dl.sourceforge.net/project/ss5/ss5/3.8.9-8/ss5-3.8.9-8.tar.gz
tar -zxvf ss5-3.8.9-8.tar.gz
cd ss5-3.8.9/
./configure
make
make install

2. 服务注册与自启

1
2
3
chmod +x /etc/init.d/ss5
chkconfig --add ss5
chkconfig ss5 on

3. 核心配置

  • 认证配置 (/etc/opt/ss5/ss5.conf):
    1
    2
    auth    0.0.0.0/0       -       u
    permit u 0.0.0.0/0 - 0.0.0.0/0 - - - - -
  • 用户密码 (/etc/opt/ss5/ss5.passwd):
    1
    username password
  • 修改端口 (/etc/sysconfig/ss5):
    1
    SS5_OPTS=" -u root -b 0.0.0.0:8899"

4. 启动与测试

1
service ss5 start  # 或 restart

使用Proxifier等客户端工具,配置代理服务器地址和端口进行连接测试。


三、 Dante 搭建方案

Dante是一个高效、配置灵活的SOCKS服务器。

1. 安装 (CentOS 7)

1
2
rpm -Uvh http://mirror.ghettoforge.org/distributions/gf/gf-release-latest.gf.el7.noarch.rpm
yum --enablerepo=gf-plus install dante-server -y

2. 基础配置 (/etc/sockd.conf)
以下是一个允许所有连接(无认证)的简单配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
errorlog: /var/log/sockd.errlog
logoutput: /var/log/sockd.log

internal: eth0 port = 1080 # 监听端口
external: eth0

method: none # 无认证

client pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
}

socks pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
}

注意:需创建日志目录 mkdir /var/run/sockd

3. 启动与管理

1
2
systemctl start sockd
systemctl enable sockd

4. 高级配置

  • 用户认证:将 method: none 改为 method: username,并使用系统用户登录。
  • 访问控制:在 client passsocks pass 块中,通过 from: / to: 字段精细控制源IP和目标地址。

四、 Squid 搭建方案 (支持正向/透明代理)

Squid主要用作HTTP代理,但也可配置为SOCKS代理,并支持强大的访问控制。

1. 安装

1
2
3
sudo apt-get install squid -y  # Ubuntu/Debian
# 或安装支持SSL的版本以启用HTTPS透明代理
sudo apt-get install squid-openssl -y

2. 基础正向代理配置

  • 编辑 /etc/squid/squid.conf,添加允许的客户端网段:
    1
    acl localnet src 172.28.0.0/16
  • /etc/squid/conf.d/debian.conf 中取消注释:
    1
    http_access allow localnet
  • 重启服务:sudo service squid restart
  • 客户端在浏览器或系统设置中配置HTTP代理为Squid服务器IP:3128。

3. 强大的访问控制示例 (在squid.conf中配置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 禁止特定IP
acl badhost src 172.28.18.7
http_access deny badhost

# 2. 禁止特定时间段
acl worktime time MTWHF 17:00-18:00
http_access deny worktime

# 3. 禁止特定域名
acl baddomain dstdomain .taobao.com .pinduoduo.com
http_access deny baddomain

# 4. 禁止访问所有IP地址(防域名绕过)
acl ipurl url_regex ^http://[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/
http_access deny ipurl

4. 透明代理配置 (需双网卡)

  • 配置Squid:在 squid.conf 中添加拦截端口。
    1
    2
    http_port 3129 intercept  # HTTP透明代理
    https_port 3130 ssl-bump cert=/etc/squid/certs/myCA.pem transparent # HTTPS透明代理
  • 生成自签名CA证书 (用于HTTPS解密):
    1
    openssl req -new -newkey rsa:4096 -sha256 -days 3650 -nodes -x509 -keyout myCA.pem -out myCA.pem
  • 配置iptables规则,将客户端的80/443流量重定向到Squid。
  • 客户端需将网关和DNS指向Squid服务器内网IP,并导入生成的CA证书。

五、 Microsocks 搭建方案 (极致轻量)

适用于内存资源紧张的VPS。

1. 安装

  • Debian/Ubuntu新版本sudo apt install microsocks
  • 旧版本或从源码安装
    1
    2
    3
    4
    wget http://ftp.barfooze.de/pub/sabotage/tarballs/microsocks-1.0.4.tar.xz
    tar -Jxf microsocks-1.0.4.tar.xz
    cd microsocks-*/
    make && sudo make install

2. 直接运行

1
microsocks -1 -u USERNAME -P PASSWORD
  • -1: 认证一次后IP加入白名单。
  • -u / -P: 用户名和密码。
  • 默认监听 0.0.0.0:1080

3. 配置为Systemd服务 (推荐)

  • 创建服务文件 /etc/systemd/system/microsocks.service
  • 创建配置文件 /etc/microsocks.conf,定义 MICROSOCKS_LOGINMICROSOCKS_PASSW
  • 启用服务:sudo systemctl enable --now microsocks

六、 客户端连接与测试

  1. **命令行测试 (Linux/Mac)**:
    1
    curl --socks5 USER:PASS@SERVER_IP:PORT https://www.google.com/
  2. 浏览器设置:在网络设置中手动配置SOCKS5代理。
  3. 专业工具:使用 Proxifier (Windows/macOS) 或 Proxy SwitchyOmega (浏览器插件) 进行全局或按规则代理。
  4. **环境变量 (Linux)**:
    1
    2
    export http_proxy=socks5://SERVER_IP:PORT
    export https_proxy=socks5://SERVER_IP:PORT

七、 故障排查

  1. 连接失败
    • 检查服务器防火墙/安全组规则是否放行代理端口。
    • 确认代理服务正在运行 (systemctl status xxx)。
    • 查看服务日志 (journalctl -xe, /var/log/xxx.log)。
  2. 认证失败:检查配置文件的用户名/密码部分,确保无拼写错误。
  3. Squid HTTPS代理失败:确保使用了 squid-openssl,正确生成并配置了CA证书,且客户端已导入该证书。

八、 总结与建议

  • 追求轻量与简单:首选 Microsocks
  • 需要稳定完整的SOCKS5服务:选择 SS5Dante
  • 主要需求是Web缓存和复杂的内容过滤:选择 Squid
  • 生产环境:务必配置用户认证和基于IP的**访问控制列表(ACL)**,并定期检查日志。

请根据您的具体需求(性能、功能、易用性、资源占用)选择最合适的方案进行部署。

一、开启 Docker Compatibility 模式

在 Podman Desktop 设置中启用 **Experimental (Docker Compatibility)**:

1
2
3
4
5
6
# 启用后即可使用 docker CLI 语法
[user@kkbruce ~]$ docker version
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
Client: Podman Engine
Version: 5.2.3
...

二、独立安装 Docker CLI

因未安装 Docker Desktop,需通过 winget 独立安装:

1
PS C:\> winget install Docker.DockerCLI

安装完成后重启 PowerShell,验证连接:

1
2
3
4
5
6
7
8
9
PS C:\> docker version
Client:
Version: 27.3.1
Context: default

Server: linux/amd64/fedora-40
Podman Engine:
Version: 5.2.3
...

三、验证 Docker CLI 与 Podman 整合

1
2
3
4
5
6
7
8
9
# 拉取镜像
PS C:\> docker pull nginx

# 确认镜像列表
PS C:\> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 60c8a892f36f 6 weeks ago 196MB
mcr.microsoft.com/dotnet/aspnet 8.0 6d7e7cb08845 5 days ago 221MB
webapplication1 dev e6090be04289 2 minutes ago 221MB

四、Visual Studio Container Tools 正常运行

创建 ASP.NET Core MVC 项目并启用容器支持,确认:

  • 无错误信息
  • Container Tools 正常运行
  • 可成功构建镜像、运行容器

关键技术点

项目 说明
Podman Desktop Windows 环境运行 WSL2,后端为 podman-machine
Docker CLI Context npipe:////./pipe/docker_engine 与 Podman 通信
Experimental Compatibility 启用后 docker CLI 可兼容操作 Podman
独立 Docker CLI 通过 winget 安装 Docker.DockerCLI

待补充

  • Podman Compose 替代 Docker Compose
  • Kubernetes 集群整合验证
  • 多阶段构建 Dockerfile 优化
0%