目标是让网站在后台每月进行一次用户统计,考虑过直接在数据库操作,但是最后还是选择直接在程序内实现。

虽然功能是实现了,但是看过文档和其他解释后还没能理解,所以这里只写How不写Why。

环境

  • dotnet core 2.1

参考

步骤

官方一共写了三种后台任务用例,分别为Timed background tasks(定时任务)、scoped service background tasks(有作用域服务) 和 Queued background tasks(队列任务)。

对于定时向数据库写入内容,我的实现方式是 timed bg task + scoped service 结合,即在定时任务内执行有作用域的服务(数据库操作)。一开始尝试只用定时方式,但是数据库的上下文依赖注入一直失败,之后在StackOverflow上找到了需要实现一样功能的人,发现他的写法结合了两种方式,最后添加了scoped service方式后成功写入数据库。

  1. 首先实现scoped service,在类中添加接口,以及实现接口的类,在类中写入数据库相关代码
    public class DbOperation {
        internal interface IScopedProcessingService {
            void DoWork();
        }
    
        internal class ScopedProcessingService : IScopedProcessingService {
            private readonly TestDbContext db;
    
            public ScopedProcessingService(TestDbContext _db) {
                db = _db;
            }
    
            ... ...
    
            public void DoWork() {
                var user = new User() {
                    name = GetRandomName(),
                    age = GetRandomAge()
                };
    
                db.Users.Add(user);
                db.SaveChanges();
            }
        }
    }

    DbOperation中定义了接口IScopedProcessingService和接口实现ScopedProcessingServiceScopedProcessingService中实现了接口中声明的,向数据库写入新条目的方法DoWork()

  2. 新建定时任务类,并在定时执行的方法中调用数据库操作服务
    internal class WriteToDb : IHostedService, IDisposable {
        private readonly ILogger logger;
        private Timer timer;
    
        public WriteToDb(ILogger<WriteToDb> _logger, IServiceProvider services) {
            Services = services;
            logger = _logger;
        }
    
        public IServiceProvider Services { get; }
    
        public Task StartAsync(CancellationToken cancellationToken) {
            logger.LogInformation("Starting");
    
            timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromHours(1)); //新建定时任务
    
            return Task.CompletedTask;
        }
    
        public void DoWork(object state) { //数据库服务
            using (var scope = Services.CreateScope()) {
                var scopedProcessingService =
                    scope.ServiceProvider.GetRequiredService<DbOperation.IScopedProcessingService>();
    
                scopedProcessingService.DoWork(); //调用写入新条目的方法
            }
            logger.LogInformation("Insert New User");
        }
    
        public Task StopAsync(CancellationToken cancellationToken) {
            logger.LogInformation("Stopping");
    
            timer?.Change(Timeout.Infinite, 0);
    
            return Task.CompletedTask;
        }
    
        public void Dispose() {
            timer?.Dispose();
        }
    }

    IHostedService中,StartAsync()StopAsync() 是必须实现的方法。应用程序准备好时会触发 StartAsync(),在应用程序“优雅地”关闭(原文:graceful shutdown)时,会触发 StopAsync()

    通过修改新建定时器的最后一个参数(代码中为TimeSpan.FromHours(1)) 来改变任务执行的周期,修改第三个参数(代码中为TimeSpan.Zero)来更改程序启动后执行任务的延时——指定为TimeSpan.Zero则在程序启动后立刻执行一次任务。

  3. 在Startup.cs中依赖注入
    public void ConfigureServices(IServiceCollection services) {
        ... ...
    
        services.AddHostedService<WriteToDb>();
        services.AddScoped<DbOperation.IScopedProcessingService, DbOperation.ScopedProcessingService>();
    
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

Continue reading “ASP.NET Core 通过 IHostedService 实现后台任务运行”

MTProxy使用MTProto协议,是专门为TG打造的代理工具。

环境

  • Ubuntu 16.04

参考&项目地址

步骤

整个过程很简单,ctrl+c、ctrl+v Github页面ReadMe的指令即可。

  1. 安装(编译)依赖
    apt install git curl build-essential libssl-dev zlib1g-dev
  2. clone MTProxy源
    git clone https://github.com/TelegramMessenger/MTProxy
    cd MTProxy
  3. 编译
    make && cd objs/bin

    如果编译失败,先执行

    make clean

    来清除编译失败的文件,然后再次编译

  4. 运行
    1. 生成密钥,用来连接TG的服务器
      curl -s https://core.telegram.org/getProxySecret -o proxy-secret
    2. 生成当前版本的TG设置,官方说明设置经常会变动,建议一天更新一次
      curl -s https://core.telegram.org/getProxyConfig -o proxy-multi.conf
    3. 生成代理密钥,用户输入此密钥来连接代理
      head -c 16 /dev/urandom | xxd -ps

      复制输出的内容

    4. 运行MTProxy
      ./mtproto-proxy -u nobody -p 8888 -H 443 -S <secret> --aes-pwd proxy-secret proxy-multi.conf -M 1

      使用上一步生成的密钥替换“<secret>”,最后的-M参数可自行设定,越大性能越好,对服务器的要求越高。

  5. 分享代理链接
    • 可以以 tg://proxy?server=SERVER_NAME&port=PORT&secret=SECRET 的形式自行编辑生成连接
    • 也可以通过关注TG官方代理Bot(@MTProxybot),根据提示输入代理信息来生成链接

frp——fast reverse proxy,可以快速的进行内网穿透的部署,通过具有公网IP的计算机访问内网计算机(具体可以用作代理个人计算机上的网站、访问NAS、远程桌面办公等)。

自从TeamViewer被强行检测为商业用途,就彻底不再使用这个软件了(中间联系商家解封一次,后来继续封),转投Splashtop(比TeamViewer便宜得多),一直听说frp,今天有空测试一下,感觉良好,但是远程桌面我还是暂选Splashtop。

环境

  • Ubuntu 18.04 虚拟机
  • Windows 7 虚拟机
  • 国内公网IP VPS

参考

步骤

基本使用

  1. 先尝试代理一个静态页面,以熟悉frp的工作方式。我在Ubuntu虚拟机中安装了nginx,并对nginx的默认页面进行了一点小修改,以便区分访问的是否为虚拟机本机的页面(我的中转VPS也安装了nginx):左上角的IP为本地地址
  2. 首先配置frp服务端,在项目发布页面下载相应压缩包,解压
    tar xvf your/path/here/frp_0.25.1_linux_amd64.tar.gz
  3. 进入frp目录,编辑frps.ini配置文件,自行设置[common]下的bind_port字段,退出保存
    [common]
    bind_port = [your port number here]
    #如果要开启验证,设置token
    token = [your password here]
  4. 运行frps可执行文件
    #可以使用screen来保持后台运行
    screen -R frp
    #注意加-c [配置文件路径] 参数,否则无法验证token
    ./frps -c frps.ini
  5. 回到Ubuntu虚拟机,同样下载frp压缩包,解压到本地,配置文件夹中的frpc.ini
    [common]
    server_addr = [VPS的公网IP]
    server_port = [服务端的端口]
    
    [Nginx Default Page] # 随意填写名字,不能重复
    type = tcp
    local_ip = 127.0.0.1
    local_port = 80 # 填写本地需要代理的端口
    remote_port = [服务端开启的端口]
  6. 然后运行frpc可执行文件
    # 同样指定-c [配置文件路径]参数
    ./frpc -c frpc.ini
  7. 如果成功绑定端口,本地会显示:
  8. 浏览器中访问 [IP地址]:[remote_port]:左上角为公网地址

Windows远程桌面

Continue reading “frp的基本使用以及Windows远程桌面的设置”