编程我只用CPP 发布的文章

年纪越来越大,记忆越来越差,笔记这个东西也是越来越有用了。最开始的时候都是用手机的便签本记笔记,由于一次刷机导致便签app没有了,也是搞笑。

后来自己搭了一个云笔记服务,用了一段时间之后由于服务器总是被攻击,为了安全起见还是放弃了使用,转投有道云。有道云好用是好用,就是广告太多了,这对于一个强迫症患者来说简直就是噩梦,也算是突发奇想百度了一下去广告,没想到还真有。

- 阅读剩余部分 -

一、概述

su 命令用来用来切换用户身份,例如:su root 切换到root 用户,su www 切换到www 用户。

su - 命令同样也是用来切换用户身份的,和su 命令不同的是,su - 在切换用户的同时也会切换shell ,这样就导致了用户的环境变量也会变化。

- 阅读剩余部分 -

一、channel

管道(channel)是golang中用于多协程通信的手段,也是go编程中常用到的数据类型。

虽然被称为管道,但是并非在《unix环境高级编程》中说的管道(fifo和pipe),go中的管道实际上是一种通过共享内存来实现的多线程通信方式,只是名字叫做管道而已。和fifo和pipe这两者没有任何关系。

创建一个管道的方法:

msg := make(chan string, 3)

其中的chan string表明管道是string类型,后面的3是管道容量。创建管道时如果指定了管道容量,管道就是一个有缓冲的管道。也可以省略3表示当前是一个无缓冲的管道,一般不建议使用无缓冲管道,可能导致程序阻塞。有缓冲管道和无缓冲管道的区别:

  1. 无缓冲管道:管道中没有元素的时候,读端会阻塞。管道有元素没有被读出的时候,写端阻塞。
  2. 有缓冲管道:管道中没有元素的嘶吼,读端会阻塞。管道中元素满了,写端阻塞。

管道的读写操作方法:

// 写管道
msg <- "HelloWorld"
// 读管道
val <- msg

示例

以下是一个无缓冲chan的执行示例,代码中分别创建两个goroutine,一个从管道读,一个往管道写,写端是在休眠一秒后才写。两个goroutine通过WaitGroup来同步结束状态:

func main() {
    var wg sync.WaitGroup
    msg := make(chan string)

    wg.Add(2)
    go func() {
        glog.Info("wait to msg...")
        glog.Info("receive msg: ", <-msg)
        wg.Done()
    }()

    go func() {
        time.Sleep(time.Second)
        msg <- "HelloWorld"
        wg.Done()
    }()

    wg.Wait()
}
代码中的输出使用glog来打印,方便输出更多信息。

输出结果:

管道接收方一共打印了两条日志,一条是协程刚启动准备接受消息时候的日志,一条是收到消息后的日志。对比两条日志的打印时间能看到中间间隔了1秒,这一秒刚好是管道发送方在睡眠,说明接收方在这一秒是在等待发送方发送数据,没有数据的时候被阻塞了。

使用无缓冲区管道千万要注意的就是阻塞,如果处理不当,读端没有及时读或者读端挂了,很可能就导致业务阻塞。

二、基于管道的异步调用

高并发场景中,一种经常用到的处理操作是异步调用,如何通过管道来实现异步调用呢?

以下是一段基于管道实现的异步调用示例,代码模拟了一次异步任务处理过程:主线程需要处理一个任务(耗时1秒),同时还要从数据库中读取一个字符串的数据。

func main() {
    var wg sync.WaitGroup
    msg := make(chan string)

    wg.Add(1)

    go func() { // 创建新的协程从数据库获取字符串
        glog.Info("service start!")
        msg <- "HelloWorld"
        glog.Info("service done!")
        wg.Done()
    }()

    glog.Info("doJob...")
    time.Sleep(time.Second) // 主线程执行任务

    glog.Info("service return: ", <-msg)
    wg.Wait()
}

程序运行结果:

从四条日志的打印时间来看,程序一共执行了大约1秒钟的时间,doJobservice start!几乎同时输出,两者在同时执行。过了一秒钟后,主函数执行完成,再从管道获取字符串数据,这样就省去了一次获取字符串数据的逻辑。假设获取字符串需要0.5秒,就节省了0.5秒的时间。

如果不使用这个异步的操作,那么整个函数的流程应该是:

  1. 主函数执行任务(1秒)
  2. 执行完成后再获取字符串数据(0.5秒)
  3. 函数结束(总耗时1.5秒)

使用异步之后,效率明显变高了。

三、有缓冲的管道

有缓冲的管道和无缓冲的管道最大的区别是往有缓冲管道内些数据时,如果管道还存在空间,写操作就不会阻塞,而无缓冲管道只要没有读端读出管道内数据,就会一直阻塞。

从上面的示例来看,msg是一个无缓冲区的管道,因此在创建的goroutine中写入数据后被阻塞,直到1秒后才打印出server done!。对这个协程而言,这1秒钟的过程无需阻塞,因为它的任务就是提取一个字符串消息然后放到管道,把数据放到管道后它的任务就完成了,可以直接结束了。没必要等到主函数读完才结束,否则很多协程都这样阻塞,纯粹浪费系统资源,降低性能。

那么这里就可以使用有缓冲区的管道来改进这一点,给管道设置一个缓冲区,新的协程往里面写数据就不会阻塞了,写完就能退出。代码中只需要修改msg创建时候的大小就可以了:

msg := make(chan string, 1)

执行结果:

可以看到,新协程启动和结束都是非常快速地,并没有等到一秒后才退出。同时主函数也在一秒后读到了字符串。

一、说明

今天进博客的时候发现所有页面都被植入了广告,气愤之余也是非常的震惊,没想到我一个日访问流量不超过10的小网站还能引起黑客的注意,而且服务器还一直收到暴力破解的请求,几秒钟就有一次,实在是难以理解。

博客建起到现在差不多三个多月,刚搭起的时候也是想过安全问题,当时只是觉得别人怎么看得上 我这一个小网站,一没流量二没钱,所以一直没有深入研究安全问题。也是直到今天才发现这个观点有问题,所以花了小半天研究了一下。

- 阅读剩余部分 -

社交生活越来越少,越来与不喜欢把生活和个人情绪都往公共空间放了,QQ、微信、微博这一些的都已经基本是要废了。更多的生活状态都只是装在心里,不再愿意展现出来,也逐渐开始习惯用博客记录下生活的点滴,平常的生活、学习或是其他。

wordpress  确实是个好东西,很多时候有些话想说了写在这里在合适不过了,只是不太和谐的是就算是写几句话也得弄篇文章出来,这就有点费劲了,所以还是更希望有个类似说说  的功能,几条简单的语句表达出来就行。

- 阅读剩余部分 -

前面成功启动了ngrok 服务,不好的是服务不是后台运行的,一旦关闭终端程序就会终止,这里我们可以把ngrok 添加到supervisor 中去让它以守护进程形式运行。

新建一个supervisor 子程序的配置文件ngrok.ini放到/etc/supervisor目录下,写入以下配置:

[program:ngrok]
directory = /usr/local/ngrok/
command = /usr/local/ngrok/bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="ngrok.dyxmq.cn" -httpAddr=":9080" -httpsAddr=":8443" -tunnelAddr=":9001"
autostart = true     ; 在 supervisord 启动的时候也自动启动
startsecs = 5        ; 启动 5 秒后没有异常退出,就当作已经正常启动了
autorestart = true   ; 程序异常退出后自动重启
startretries = 3     ; 启动失败自动重试次数,默认是 3
user = root          ; 用哪个用户启动
redirect_stderr = true  ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 20MB  ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 20     ; stdout 日志文件备份数
stdout_logfile = /var/log/supervisor/ngrok.log

更多supervisor 相关资料:http://www.dyxmq.cn/tag/supervisor/

一、概述

ngrok  是一个反向代理的内网穿透服务器,用于把没有公网地址的内网主机映射到公网,常被用于微信后台开发。

ngrok  使用go  语言编写,目前版本2.1 ,开源版本为1.7 存在内存泄漏且不稳定,长时间使用会导致资源占用异常,不适合长久使用,需要稳定版可以去购买正版。

环境要求:公网主机,域名。

二、环境准备

1.安装go语言环境

软件基于go  语言编写,需要先安装go  语言环境,安装方法详见:linux安装Go1.9.2

2.安装git

go  语言安装依赖包时需要用到git ,安装方法:centos源码安装git

- 阅读剩余部分 -