威联通NAS安装配置AList+Aria2并实现NAS下载网盘中的文件到本地

背景 使用威联通远程下载各种网盘中的文件,主要分为三步: 安装AList,挂载网盘。 安装Aria2,并配置RPC。 在AList中配置Aria2的RPC链接,实现下载。 建议配合Tailscale局域网虚拟组网使用,实现公司等任何地点都可以下载资源。 下载AList威联通手动安装包 https://github.com/iranee/qnap-alist-webdav/releases 根据自己的机器选择对应的文件。 x86架构:alist_3.38.0_x86_64.qpkg arm架构:alist_3.38.0_arm_64.qpkg 如果网络不行可以下载我整理好的文件,夸克链接:https://pan.quark.cn/s/9130f0e533d2 手动安装 进入威联通管理后台 打开AppCenter 右上角手动安装按钮 点击左边的浏览按钮选择刚才下载的的文件 点击右边的安装按钮 等待安装完成 去桌面点击AList图标即可跳转打开 修改密码 Alist的默认账号密码是:账号:admin 密码:123456 进入系统先修改密码,如果忘记了密码可以通过ssh连接威联通 # 进入AList安装目录 cd /share/CACHEDEV1_DATA/.qpkg/alist # 查看管理员信息,低于v3.25.0版本可直接查看密码 ./alist admin # 高于v3.25.0版本 # 随机生成一个密码 ./alist admin random # 手动设置一个密码,`NEW_PASSWORD`是指你需要设置的密码 ./alist admin set NEW_PASSWORD 配置下载工具 安装Aria2 下载Aria2威联通安装包 https://www.myqnap.org/product/aria2/ 夸克链接:https://pan.quark.cn/s/2a392c41cc01 手动安装Aria2 威联通控制台->网络访问->应用程序->Web服务器->启用(参数不用改) 配置Aria2 通过ssh或者其他软件登录威联通服务器(不是页面那个后台),进入威联通后台点击Aria2即可进入AriaNg页面 进入AriaNg页面->Aria2设置->基本设置->下载路径,修改为自己的存储位置,否则默认文件会下载到/share/CACHEDEV1_DATA/.qpkg/AriaII这个安装目录 修改aria2.conf配置文件 # 打开配置文件 vim /share/CACHEDEV1_DATA/.qpkg/AriaII/aria2.conf # rpc-secret这个key对应的值就是Aria2 RPC密钥,复制出来一会儿要填入AriaNg设置->RPC设置 # 将下面这行添加进去,这个很关键,因为AList调用Aria2需要请求http协议的Aria2 RPC,不加这个参数会报跨域请求错误 rpc-allow-origin-all=true 威联通后台AppCenter中找到Aria2,先停止在打开重启一下Aria2 进入AriaNg页面->AriaNg设置->添加RPC,地址就填威联通的局域网地址,端口默认6800,路径默认jsonrpc,密钥填刚才复制出来的rpc-secret,配置完Aria2状态应该会显示已连接 配置AList 参考AList官网文档挂载网盘 AList网盘页面右下角点击本地设置,填入Aria2 RPC 链接,类似这种格式http://127.0.0.1:6800/jsonrpc,地址改成威联通的内网地址。 下载文件到NAS本地 找到网盘中要下载到本地的文件,选中之后页面底部会弹出来一排按钮,点击下载,选择发送到Aria2,就可以自动下载了。 原文地址 威联通NAS安装配置AList并实现NAS下载网盘中的文件到本地 ...

December 24, 2024 · 1 min · 78 words · 姜红杰

网络编程TCP socket简单demo

通过该简单的demo学习socket网络编程,注释会详细解释每一行的作用,并且代码可以编译运行。 server.c #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <sys/time.h> /* timeval{} for select() */ #include <time.h> /* timespec{} for pselect() */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <errno.h> #include <fcntl.h> /* for nonblocking */ #include <netdb.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> /* for S_xxx file mode constants */ #include <sys/uio.h> /* for iovec{} and readv/writev */ #include <unistd.h> #include <sys/wait.h> #include <sys/un.h> /* for Unix domain sockets */ #include <sys/select.h> /* for convenience */ #include <sys/sysctl.h> #include <poll.h> /* for convenience */ #include <strings.h> /* for convenience */ #include <sys/ioctl.h> #include <pthread.h> size_t readn(int fd, void *buffer, size_t size) { char *buffer_pointer = buffer; int length = size; while (length > 0) { int result = read(fd, buffer_pointer, length); if (result < 0) { if (errno == EINTR) continue; /* 考虑非阻塞的情况,这里需要再次调用read */ else return (-1); } else if (result == 0) break; /* EOF(End of File)表示套接字关闭 */ length -= result; buffer_pointer += result; } return (size - length); /* 返回的是实际读取的字节数*/ } void read_data(int sockfd) { ssize_t n; char buf[1024]; int time = 0; for (;;) { fprintf(stdout, "block in read\n"); if ((n = readn(sockfd, buf, 1024)) == 0) return; time++; fprintf(stdout, "1K read for %d \n", time); // 接收设置延迟时间,观察client发送数据和server接收数据,client将数据写入到缓冲区之后就会立即返回成功 sleep(5); } } int main(int argc, char **argv) { int listenfd, connfd; socklen_t clilen; // 声明地址信息结构体 struct sockaddr_in cliaddr, servaddr; // 创建套接字 listenfd = socket(AF_INET, SOCK_STREAM, 0); // 将指定内存区域的前 n 个字节全部设置为零,用于初始化内存区域 bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; // INADDR_ANY IPv4通配地址 IN6ADDR_ANY IPv6通配地址 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 设置端口号,设置为0时由操作系统选择一个空闲的端口 // htons函数:将一个无符号短整型(通常是16位)的主机数值转换为网络字节顺序 servaddr.sin_port = htons(12345); // bind到本地地址,端口为12345 // bind函数套接字和地址关联 bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); // 初始化创建的套接字,可以认为是一个"主动"套接字,其目的是之后主动发起请求 // 通过 listen 函数,可以将原来的"主动"套接字转换为"被动"套接字 listen(listenfd, 1024); /* 循环处理用户请求 */ for (;;) { clilen = sizeof(cliaddr); // 客户端发起连接请求,accept函数接受请求建立连接 // 第一个参数listenfd是用于监听的套接字,返回的是新建立连接的套接字 connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); read_data(connfd); /* 读取数据 */ close(connfd); /* 关闭连接套接字,注意不是监听套接字*/ } } client.c #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <sys/time.h> /* timeval{} for select() */ #include <time.h> /* timespec{} for pselect() */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <errno.h> #include <fcntl.h> /* for nonblocking */ #include <netdb.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> /* for S_xxx file mode constants */ #include <sys/uio.h> /* for iovec{} and readv/writev */ #include <unistd.h> #include <sys/wait.h> #include <sys/un.h> /* for Unix domain sockets */ #include <sys/select.h> /* for convenience */ #include <sys/sysctl.h> #include <poll.h> /* for convenience */ #include <strings.h> /* for convenience */ #include <sys/ioctl.h> #include <pthread.h> #include <stdarg.h> /* ANSI C header file */ #include <syslog.h> /* for syslog() */ # define MESSAGE_SIZE 102400 void error(int status, int err, char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if (err) fprintf(stderr, ": %s (%d)\n", strerror(err), err); if (status) exit(status); } void send_data(int sockfd) { char *query; query = malloc(MESSAGE_SIZE + 1); for (int i = 0; i < MESSAGE_SIZE; i++) { query[i] = 'a'; } query[MESSAGE_SIZE] = '\0'; const char *cp; cp = query; size_t remaining = strlen(query); while (remaining) { int n_written = send(sockfd, cp, remaining, 0); fprintf(stdout, "send into buffer %d \n", n_written); if (n_written <= 0) { error(1, errno, "send failed"); return; } remaining -= n_written; cp += n_written; } return; } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; if (argc != 2) error(1, 0, "usage: tcpclient <IPaddress>"); sockfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(12345); inet_pton(AF_INET, argv[1], &servaddr.sin_addr); int connect_rt = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); if (connect_rt < 0) { error(1, errno, "connect failed "); } send_data(sockfd); exit(0); } 对于 send 来说,返回成功仅仅表示数据写到发送缓冲区成功,并不表示对端已经成功收到。 对于 read 来说,需要循环读取数据,并且需要考虑 EOF 等异常条件。 ...

December 12, 2024 · 3 min · 628 words · 姜红杰

PHP模型对应表字段注释属性快速生成

背景 以下内容基于thinkphp5.1框架和phpstrom编辑器进行说明 php web项目业务开发中绝大部分都是使用MVC结构的框架,在添加和更新数据时基本都支持实例化模型对象后赋值并保存。比如: $user = new User; $user->name = 'test'; $user->email = 'test@qq.com'; $user->save(); 其中name和email都对应user表的字段。这里编辑器不知道User表的表字段也就无法自动提示,意味着你要记住表的字段或者一边看表一边进行开发。 模型字段注释 针对上面的情况可以在User模型类中添加user表的字段注释来实现自动提示,开发时只需要记得字段大概的名称或者去User模型类中看注释即可知道表的结构。 <?php namespace app\user\model; use think\Model; /** * Class User * @property int member_id 主键 * @property varchar name 会员名称 * @property varchar email 邮箱 * @property varchar member_role 用户角色 * @property char passwd 密码 * @property int add_time 添加时间 * @property int update_time 最后一次修改时间 * @package app\user\model * @author jianghongjie */ class User extends Model { // 定义主键 protected $pk = 'member_id'; //开启自动时间戳 protected $autoWriteTimestamp = true; // 创建时间 protected $createTime = 'add_time'; // 更新时间 protected $updateTime = 'update_time'; } 快速生成模型字段注释 当表的字段很多或者表很多时写注释也很费时间和精力,使用下面的sql可以快速生成一个表的模型字段注释 ...

October 14, 2020 · 1 min · 152 words · 姜红杰

Golang应用打包docker镜像并运行

使用gin框架起一个最基础的web服务来说明整个流程。 编写程序代码 main.go package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run("0.0.0.0:8080") // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080") } 这里需要注意的是docker里面的host不能配置127.0.0.1或者192.168.0.1否则宿主机器将无法访问端口。所以这里服务启动时要绑定在0.0.0.0上。 编写Dockerfile文件 FROM golang:alpine MAINTAINER JiangHongJie "jhj767658181@gmail.com" # docker中的工作目录 WORKDIR $GOPATH/src/gin_docker # 将当前目录同步到docker工作目录下,也可以只配置需要的目录和文件(配置目录、编译后的程序等) ADD . ./ # 由于所周知的原因,某些包会出现下载超时。这里在docker里也使用go module的代理服务 ENV GO111MODULE=on ENV GOPROXY="https://goproxy.io" # 指定编译完成后的文件名,可以不设置使用默认的,最后一步要执行该文件名 RUN go build -o gin_docker . EXPOSE 8080 # 这里跟编译完的文件名一致 ENTRYPOINT ["./gin_docker"] 构建docker镜像 sudo docker build -t gin_docker . 构建完成查看镜像列表 vagrant@homestead:~/go_project/gin_docker$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE gin_docker latest ed64de3e98e9 2 hours ago 469MB logforce latest 3cfe19164260 3 hours ago 511MB <none> <none> d20ebc82d1e6 6 hours ago 810MB <none> <none> c19c1e8968e1 6 hours ago 828MB golang alpine 30df784d6206 2 weeks ago 370MB 启动容器 vagrant@homestead:~/go_project/gin_docker$ docker run --name gin_docker -p 8080:8080 -d gin_docker ae97da70bc94a4c9a235f44a7d12030b283a2fabd56fc2be1a70ffef3a805c71 vagrant@homestead:~/go_project/gin_docker$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ae97da70bc94 gin_docker "./gin_docker" 24 seconds ago Up 22 seconds 0.0.0.0:8080->8080/tcp gin_docker 访问服务 vagrant@homestead:~/go_project/gin_docker$ curl 127.0.0.1:8080/ping {"message":"pong"} 参考文章 使用 docker build 时 下载 golang.org/x 包失败

August 5, 2020 · 1 min · 171 words · 姜红杰

Golang Printf函数副词参数列表

Printf函数副词参数列表 General %v 以默认的方式打印变量的值 %T 打印变量的类型 Integer %d 整型的十进制表示 %+d 带符号的整型,fmt.Printf("%+d",255)输出+255 %q 打印单引号 %o 不带0的八进制 %#o 带0的八进制 %x 小写的十六进制 %X 大写的十六进制 %#x 带0x的十六进制 %U 打印Unicode字符 %#U 打印带字符的Unicode %b 打印整型的二进制 Integet width %5d 表示该整型最大的长度为5 %-5d 则相反,打印结果会自动左对齐 %05d 会在数字前面补0 Fload %f(=%.6f) 6位小数点 %e(=%.6e) 6位小数点(科学计数法) %g 用最少的数字来表示 %.3g 最多3位数字来表示 %.3f 最多3位小数来表示 String %s 正常输出字符串 %q 字符串带双引号,字符串中的引号带转义符 %#q 字符串带反引号,如果字符串内有反引号,就用双引号代替 %x 将字符串转换为小写的16进制格式 %X 将字符串转换为大写的16进制格式 % x 带空格的16进制格式 String width %5s 最小宽度为5 %-5s 最小宽度为5(左对齐) %.5s 最大宽度为5 %-5.7 最小宽度为5,最大宽度为7(左对齐) %5.3 如果宽度大于3则截断 %05s 如果宽度小于5,就会在字符串前面补0 Struct %v 正常打印.比如:{sam{12345 67890}} %+v 带字段名称,比如:{name:sam phone:{mobile:12345 office:67890}} %#v 用Go的语法打印,例如:main.People{name:"sam",phone:main.Phone{mobile:"12345",office:"67890"}} Boolean %t 打印布尔值true或者false Pointer %p 带0x的指针 %#p 不带0x的指针

July 27, 2020 · 1 min · 94 words · 姜红杰