008-Cpp time操作示例

Cpp time 示例

1: time 介绍

  • std::chrono::duration

  • std::chrono::time_point

  • std::chrono::system_clock

  • std::chrono::steady_clock

  • std::chrono::high_resolution_clock

  • std::time_t

  • std::tm

2: time code

 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
#include <chrono>
#include <iostream>
#include <thread>
#include <ctime>
#include <iomanip>

int main() {
    // std::chrono::duration<Rep ,Period> 表示一段时间
    std::chrono::duration<int> time_out_1(3); // time_out 设置为3S
    std::chrono::duration<int, std::ratio<1>> time_out_2(3); // time_out 设置为3S
    std::chrono::duration<int, std::milli> time_out_3(3000); // time_out 设置为3000 ms

    std::chrono::duration<int,std::ratio<1>> sum_duration =
            std::chrono::duration_cast<std::chrono::duration<int>>(time_out_1) +
            std::chrono::duration_cast<std::chrono::duration<int>>(time_out_2) +
            std::chrono::duration_cast<std::chrono::duration<int>>(time_out_3);

    std::cout << "sum_duration = " << sum_duration.count() << " seconds" << std::endl;

    std::chrono::duration<long long,std::ratio<1,1000>> sum_duration_mill =std::chrono::duration_cast<std::chrono::milliseconds>(sum_duration);
    std::cout << "sum_duration_mill = " << sum_duration_mill.count() << " millseconds" << std::endl;

    // std::chrono::time_point<>; 表示时间点
    std::chrono::system_clock::time_point t1=std::chrono::system_clock::now(); // 获取当前时间点
    std::this_thread::sleep_for(std::chrono::seconds(3)); // sleep 3 s
    std::chrono::system_clock::time_point t2=std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_time=t2-t1;

    std::cout << "Start time: " << std::chrono::system_clock::to_time_t(t1) << std::endl;
    std::cout << "End time: " << std::chrono::system_clock::to_time_t(t2) << std::endl;
    std::cout << "Time elapsed: " << elapsed_time.count() << " seconds" << std::endl;


    // std::chrono::system_clock 类提供给了从系统实时时钟上获取当前时间功能。
    // 可以调用std::chrono::system_clock::now()来获取当前的时间

    // std::chrono::steady_clock 能访问系统稳定时钟。
    // 可以通过调用std::chrono::steady_clock::now()获取当前的时间。设备上显示的时间,与使用std::chrono::steady_clock::now()获取的时间没有固定的关系。稳定时钟是无法回调的


    // td::chrono::high_resolution_clock类能访问系统高精度时钟。和所有其他时钟一样,通过调用std::chrono::high_resolution_clock::now()来获取当前时间
    // std::chrono::high_resolution_clock可能是std::chrono::system_clock类或std::chrono::steady_clock类的别名,也可能就是独立的一个类
    // 通过std::chrono::high_resolution_clock具有所有标准库支持时钟中最高的精度,这就意味着使用
    // std::chrono::high_resolution_clock::now()要花掉一些时间。所以,当你再调用std::chrono::high_resolution_clock::now()的时候,需要注意函数本身的时间开销。


    // datetime
    // 获取当前时间点
    auto now=std::chrono::system_clock::now();
    // 将时间点转为时间戳 time_t
    std::time_t time_t_now =std::chrono::system_clock::to_time_t(now);
    // 将时间戳转换为 std::tm 结构体
    std::tm* time_info = std::localtime(&time_t_now);
    std::cout << "Current DateTime: " << std::put_time(time_info, "%Y-%m-%d %H:%M:%S") << std::endl;


    return 0;
}

039-Shell设置颜色及一些参数

1: Shell 脚本查错

1.1 set -u

  • 执行脚本时,如果遇到不存在的变量,Bash 默认忽略它;
  • set -u 就用来改变这种行为。脚本在头部加上它,遇到不存在的变量就会报错,并停止执行;
1
2
3
4
5
#!/usr/bin/env bash
set -u

echo $a
echo bar
  • 运行结果如下:
1
2
3
4
$ bash script.sh
bash: script.sh:行4: a: 未绑定的变量
# 可以看到,脚本报错了,并且不再执行后面的语句
#
  • -u 还有另一种写法 -o nounset ,两者是等价的;
  • set -o nounset

1.2 set -x

  • set -x 用来在运行结果之前,先输出执行的那一行命令;
  • -x还有另一种写法-o xtrace;

1.3

1.4 Bash 的错误处理

  • [[ -d $dir_name ]] && cd $dir_name && rm *: 先判断目录存在,再删除;
  • bash 的-x参数可以在执行每一行命令之前,打印该命令;

1.5 set -e

1.6 其他参数

  • set 命令还有一些其他参数。

Linux系统常用命令速查

1: 查看系统信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
arch      #显示机器的处理器架构(1)
uname -m  #显示机器的处理器架构(2)
uname -r  #显示正在使用的内核版本
dmidecode -q          #显示硬件系统部件 - (SMBIOS / DMI)
hdparm -i /dev/hda    #罗列一个磁盘的架构特性
hdparm -tT /dev/sda   #在磁盘上执行测试性读取操作
cat /proc/cpuinfo     #显示CPU info的信息
cat /proc/interrupts  #显示中断
cat /proc/meminfo     #校验内存使用
cat /proc/swaps       #显示哪些swap被使用
cat /proc/version     #显示内核的版本
cat /proc/net/dev     #显示网络适配器及统计
cat /proc/mounts      #显示已加载的文件系统
lspci -tv   #罗列PCI设备
lsusb -tv   #显示USB设备

2: date 显示系统日期

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
1: 查看当前时间
date +"%Y-%m-%d %H:%M:%S"
# 输出:"2021-03-25 18:12:38"

2: 查看指定时间,转为时间戳
date +%s
date -d "2021-03-25 18:12:38" +"%Y-%m-%d %H:%M:%S"
date -d "2021-03-25 18:12:38" +%s

3:时间戳转换为date
date -d @1416387827
date -d @1416387827 +"%Y-%m-%d %H:%M:%S"

cal 2007              #显示2007年的日历表
date 041217002007.00   #设置日期和时间 - 月日时分年.秒
clock -w              #将时间修改保存到 BIOS

3: 系统的关机、重启以及登出

1
2
3
4
5
6
7
8
shutdown -h now    #关闭系统(1)
init 0            #关闭系统(2)
telinit 0         #关闭系统(3)
shutdown -h hours:minutes &   #按预定时间关闭系统
shutdown -c       #取消按预定时间关闭系统
shutdown -r now   #重启(1)
reboot   #重启(2)
logout   #注销

4: 文件搜索

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
find / -name file1     #从 '/' 开始进入根文件系统搜索文件和目录
find / -user user1     #搜索属于用户 'user1' 的文件和目录
find /home/user1 -name \*.bin        #在目录 '/ home/user1' 中搜索带有'.bin' 结尾的文件
find /usr/bin -type f -atime +100    #搜索在过去100天内未被使用过的执行文件
find /usr/bin -type f -mtime -10     #搜索在10天内被创建或者修改过的文件
find / -name \*.rpm -exec chmod 755 '{}' \;      #搜索以 '.rpm' 结尾的文件并定义其权限
find / -xdev -name \*.rpm        #搜索以 '.rpm' 结尾的文件,忽略光驱、捷盘等可移动设备
locate \*.ps       #寻找以 '.ps' 结尾的文件 - 先运行 'updatedb' 命令
whereis halt       #显示一个二进制文件、源码或man的位置
which halt         #显示一个二进制文件或可执行文件的完整路径

5: 挂载一个文件系统

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
mount /dev/hda2 /mnt/hda2    #挂载一个叫做hda2的盘 - 确定目录 '/ mnt/hda2' 已经存在
umount /dev/hda2            #卸载一个叫做hda2的盘 - 先从挂载点 '/ mnt/hda2' 退出
fuser -km /mnt/hda2         #当设备繁忙时强制卸载
umount -n /mnt/hda2         #运行卸载操作而不写入 /etc/mtab 文件- 当文件为只读或当磁盘写满时非常有用
mount /dev/fd0 /mnt/floppy        #挂载一个软盘
mount /dev/cdrom /mnt/cdrom       #挂载一个cdrom或dvdrom
mount /dev/hdc /mnt/cdrecorder    #挂载一个cdrw或dvdrom
mount /dev/hdb /mnt/cdrecorder    #挂载一个cdrw或dvdrom
mount -o loop file.iso /mnt/cdrom    #挂载一个文件或ISO镜像文件
mount -t vfat /dev/hda5 /mnt/hda5    #挂载一个Windows FAT32文件系统
mount /dev/sda1 /mnt/usbdisk         #挂载一个usb 捷盘或闪存设备
mount -t smbfs -o username=user,password=pass //WinClient/share /mnt/share #挂载一个windows网络共享

6: 磁盘空间

1
2
3
4
5
6
7
8
df -h           #显示已经挂载的分区列表
ls -lSr |more    #以尺寸大小排列文件和目录
du -sh dir1      #估算目录 'dir1' 已经使用的磁盘空间'
du -sk * | sort -rn     #以容量大小为依据依次显示文件和目录的大小
rpm -q -a --qf '%10{SIZE}t%{NAME}n' | sort -k1,1n
#以大小为依据依次显示已安装的rpm包所使用的空间 (fedora, redhat类系统)
dpkg-query -W -f='${Installed-Size;10}t${Package}n' | sort -k1,1n
#以大小为依据显示已安装的deb包所使用的空间 (ubuntu, debian类系统)

7: 用户和群组

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
groupadd group_name   #创建一个新用户组
groupdel group_name   #删除一个用户组
groupmod -n new_group_name old_group_name   #重命名一个用户组
useradd -c "Name Surname " -g admin -d /home/user1 -s /bin/bash user1     #创建一个属于 "admin" 用户组的用户
useradd user1      #创建一个新用户
userdel -r user1   #删除一个用户 ( '-r' 排除主目录)
usermod -c "User FTP" -g system -d /ftp/user1 -s /bin/nologin user1   #修改用户属性

passwd         #修改口令
passwd user1   #修改一个用户的口令 (只允许root执行)
chage -E 2005-12-31 user1    #设置用户口令的失效期限
pwck     #检查 '/etc/passwd' 的文件格式和语法修正以及存在的用户
grpck    #检查 '/etc/passwd' 的文件格式和语法修正以及存在的群组
newgrp group_name     #登陆进一个新的群组以改变新创建文件的预设群组

8: 打包和压缩文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bunzip2 file1.bz2   #解压一个叫做 'file1.bz2'的文件
bzip2 file1         #压缩一个叫做 'file1' 的文件
gunzip file1.gz     #解压一个叫做 'file1.gz'的文件
gzip file1          #压缩一个叫做 'file1'的文件
gzip -9 file1       #最大程度压缩

rar a file1.rar test_file          #创建一个叫做 'file1.rar' 的包
rar a file1.rar file1 file2 dir1   #同时压缩 'file1', 'file2' 以及目录 'dir1'
rar x file1.rar     #解压rar包
unrar x file1.rar   #解压rar包

tar -cvf archive.tar file1   #创建一个非压缩的 tarball
tar -cvf archive.tar file1 file2 dir1  #创建一个包含了 'file1', 'file2' 以及 'dir1'的档案文件
tar -tf archive.tar    #显示一个包中的内容
tar -xvf archive.tar   #释放一个包
tar -xvf archive.tar -C /tmp     #将压缩包释放到 /tmp目录下
tar -cvfj archive.tar.bz2 dir1   #创建一个bzip2格式的压缩包
tar -jxvf archive.tar.bz2        #解压一个bzip2格式的压缩包
tar -cvfz archive.tar.gz dir1    #创建一个gzip格式的压缩包
tar -zxvf archive.tar.gz         #解压一个gzip格式的压缩包

zip file1.zip file1    #创建一个zip格式的压缩包
zip -r file1.zip file1 file2 dir1    #将几个文件和目录同时压缩成一个zip格式的压缩包
unzip file1.zip    #解压一个zip格式压缩包

9: linux 包管理器

9.1 RPM 包 - (Fedora, Redhat 及类似系统)

 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
rpm -ivh package.rpm    #安装一个rpm包
rpm -ivh --nodeeps package.rpm   #安装一个rpm包而忽略依赖关系警告
rpm -U package.rpm        #更新一个rpm包但不改变其配置文件
rpm -F package.rpm        #更新一个确定已经安装的rpm包
rpm -e package_name.rpm   #删除一个rpm包
rpm -qa      #显示系统中所有已经安装的rpm包
rpm -qa | grep httpd    #显示所有名称中包含 "httpd" 字样的rpm包
rpm -qi package_name    #获取一个已安装包的特殊信息
rpm -qg "System Environment/Daemons"     #显示一个组件的rpm包
rpm -ql package_name       #显示一个已经安装的rpm包提供的文件列表
rpm -qc package_name       #显示一个已经安装的rpm包提供的配置文件列表
rpm -q package_name --whatrequires     #显示与一个rpm包存在依赖关系的列表
rpm -q package_name --whatprovides    #显示一个rpm包所占的体积
rpm -q package_name --scripts         #显示在安装/删除期间所执行的脚本l
rpm -q package_name --changelog       #显示一个rpm包的修改历史
rpm -qf /etc/httpd/conf/httpd.conf    #确认所给的文件由哪个rpm包所提供
rpm -qp package.rpm -l    #显示由一个尚未安装的rpm包提供的文件列表
rpm --import /media/cdrom/RPM-GPG-KEY    #导入公钥数字证书
rpm --checksig package.rpm      #确认一个rpm包的完整性
rpm -qa gpg-pubkey      #确认已安装的所有rpm包的完整性
rpm -V package_name     #检查文件尺寸、 许可、类型、所有者、群组、MD5检查以及最后修改时间
rpm -Va                 #检查系统中所有已安装的rpm包- 小心使用
rpm -Vp package.rpm     #确认一个rpm包还未安装
rpm2cpio package.rpm | cpio --extract --make-directories *bin*   #从一个rpm包运行可执行文件
rpm -ivh /usr/src/redhat/RPMS/`arch`/package.rpm    #从一个rpm源码安装一个构建好的包
rpmbuild --rebuild package_name.src.rpm       #从一个rpm源码构建一个 rpm 包

9.2 YUM 软件包升级器 - (Fedora, RedHat 及类似系统)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
yum install package_name             #下载并安装一个rpm包
yum localinstall package_name.rpm    #将安装一个rpm包,使用你自己的软件仓库为你解决所有依赖关系
yum update package_name.rpm    #更新当前系统中所有安装的rpm包
yum update package_name        #更新一个rpm包
yum remove package_name        #删除一个rpm包
yum list                   #列出当前系统中安装的所有包
yum search package_name     #在rpm仓库中搜寻软件包
yum clean packages          #清理rpm缓存删除下载的包
yum clean headers           #删除所有头文件
yum clean all                #删除所有缓存的包和头文件

9.3 DEB 包 (Debian, Ubuntu 以及类似系统)

1
2
3
4
5
6
7
8
dpkg -i package.deb     #安装/更新一个 deb 包
dpkg -r package_name    #从系统删除一个 deb 包
dpkg -l                 #显示系统中所有已经安装的 deb 包
dpkg -l | grep httpd    #显示所有名称中包含 "httpd" 字样的deb包
dpkg -s package_name    #获得已经安装在系统中一个特殊包的信息
dpkg -L package_name    #显示系统中已经安装的一个deb包所提供的文件列表
dpkg --contents package.deb    #显示尚未安装的一个包所提供的文件列表
dpkg -S /bin/ping              #确认所给的文件由哪个deb包提供

9.4 APT 软件工具 (Debian, Ubuntu 以及类似系统)

1
2
3
4
5
6
7
8
apt-get install package_name      #安装/更新一个 deb 包
apt-cdrom install package_name    #从光盘安装/更新一个 deb 包
apt-get update      #升级列表中的软件包
apt-get upgrade     #升级所有已安装的软件
apt-get remove package_name     #从系统删除一个deb包
apt-get check     #确认依赖的软件仓库正确
apt-get clean     #从下载的软件包中清理缓存
apt-cache search searched-package    #返回包含所要搜索字符串的软件包名称

10: 查看文件内容

1
2
3
4
5
6
7
cat file1      #从第一个字节开始正向查看文件的内容
tac file1      #从最后一行开始反向查看一个文件的内容
more file1     #查看一个长文件的内容
less file1     #类似于 'more' 命令,但是它允许在文件中和正向操作一样的反向操作
head -2 file1    #查看一个文件的前两行
tail -2 file1    #查看一个文件的最后两行
tail -f /var/log/messages     #实时查看被添加到一个文件中的内容

11: 文本处理

 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
cat file1 file2 ... | command <> file1_in.txt_or_file1_out.txt general syntax for text manipulation using PIPE, STDIN and STDOUT

cat file1 | command( sed, grep, awk, grep, etc...) > result.txt
#合并一个文件的详细说明文本,并将简介写入一个新文件中
cat file1 | command( sed, grep, awk, grep, etc...) >> result.txt
#合并一个文件的详细说明文本,并将简介写入一个已有的文件中

grep Aug /var/log/messages     #在文件 '/var/log/messages'中查找关键词"Aug"
grep ^Aug /var/log/messages    #在文件 '/var/log/messages'中查找以"Aug"开始的词汇
grep [0-9] /var/log/messages   #选择 '/var/log/messages' 文件中所有包含数字的行
grep Aug -R /var/log/*         #在目录 '/var/log' 及随后的目录中搜索字符串"Aug"

sed 's/stringa1/stringa2/g' example.txt
#将example.txt文件中的 "string1" 替换成 "string2"
sed '/^$/d' example.txt           #从example.txt文件中删除所有空白行
sed '/ *#/d; /^$/d' example.txt   #从example.txt文件中删除所有注释和空白行
echo 'esempio' | tr '[:lower:]' '[:upper:]'    #合并上下单元格内容
sed -e '1d' result.txt          #从文件example.txt 中排除第一行
sed -n '/stringa1/p'            #查看只包含词汇 "string1"的行
sed -e 's/ *$//' example.txt    #删除每一行最后的空白字符
sed -e 's/stringa1//g' example.txt
#从文档中只删除词汇 "string1" 并保留剩余全部
sed -n '1,5p;5q' example.txt     #查看从第一行到第5行内容
sed -n '5p;5q' example.txt       #查看第5行
sed -e 's/00*/0/g' example.txt   #用单个零替换多个零

cat -n file1       #标示文件的行数
cat example.txt | awk 'NR%2==1'      #删除example.txt文件中的所有偶数行
echo a b c | awk '{print $1}'        #查看一行第一栏
echo a b c | awk '{print $1,$3}'     #查看一行的第一和第三栏
paste file1 file2           #合并两个文件或两栏的内容
paste -d '+' file1 file2    #合并两个文件或两栏的内容,中间用"+"区分

sort file1 file2              #排序两个文件的内容
sort file1 file2 | uniq       #取出两个文件的并集(重复的行只保留一份)
sort file1 file2 | uniq -u    #删除交集,留下其他的行
sort file1 file2 | uniq -d    #取出两个文件的交集(只留下同时存在于两个文件中的文件)

comm -1 file1 file2    #比较两个文件的内容只删除 'file1' 所包含的内容
comm -2 file1 file2    #比较两个文件的内容只删除 'file2' 所包含的内容
comm -3 file1 file2    #比较两个文件的内容只删除两个文件共有的部分

go将html转为image图片

go将html转为image图片

1: 概述

2: go 代码

  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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package pkgs

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

// 用于从 HTML/CSS 生成高质量图像的 API
// https://docs.htmlcsstoimage.com/
const (
	userID = "c721cbd9-9ddf-4efb-b97c-0616490d98ac"
	apiKey = "aa7c90f4-b2ef-4a6c-85af-e24141c10750"
)

func My_Image() {
	data := map[string]string{
		// "html": `"<div class='ping'>Pong ✅</div>"`,
		"device_scale": "1",
		"html": fmt.Sprintf(`
<div style="height: 455px; width: 1068px;  ">
    <style>
        .line {
            background-color: #f2f2f2;
        }
    </style>
    <table border: 1px solid;>
        <tr class='title' bgcolor='#008888'>
            <th style="width: 100px;">Host</th>
            <th style="width: 150px;">Account</th>
            <th style="width: 50px;">StatusCode</th>
            <th style="width: 100px;">Status</th>
            <th style="width: 666px;">ErrMsg</th>
        </tr>
        <tr class='line' >
            <td>192.168.8.1</td>
            <td>mshw_ms03</td>
            <td>1</td>
            <td>PENDING_CANCEL</td>
            <td>INVALID_BOC_TYPE_BY_CLIENT</td>
        </tr>
        <tr class='line'>
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>2</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>3</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>4</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>5</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>6</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>1</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>2</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
    </table>
</div>`),
	}

	reqBody, err := json.Marshal(data)
	if err != nil {
		log.Fatalf("unable to marshal data: %s", err.Error())
	}
	req, err := http.NewRequest("POST", "https://hcti.io/v1/image", bytes.NewReader(reqBody))
	if err != nil {
		log.Fatalf("unable to create new request: %s", err.Error())
	}
	req.SetBasicAuth(userID, apiKey)
	client := &http.Client{Timeout: time.Second * 10}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("request was unsuccessful: %s", err.Error())
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("unable to read response body: %s", err.Error())
	}
	fmt.Println(string(body)) // 在线online图片的连接
}

007-Cpp debug 工具dbg-macro

Cpp debug 工具dbg-macro

1: 介绍

  • https://github.com/sharkdp/dbg-macro
  • 打日志是 C++ 开发中必不可少的一种 debug 方式,dbg-macro 受 Rust 语言中 的 dbg 启发,提供比 printf 和 std::cout 更好的宏函数。主要有如下特点:
    • 美观的彩色输出(当输出不是交互式终端时,颜色将自动禁用)
    • 兼容 C++11,并且是 header-only
    • 支持基础类型和 STL 容器类型的输出
    • 可以输出文件名、行号、函数名和原始表达式

2:install

1
2
git clone https://github.com/sharkdp/dbg-macro
sudo ln -s $(readlink -f dbg-macro/dbg.h) /usr/include/dbg.h

2.1 On Arch Linux

  • yay -S dbg-macro

2.2 With vcpkg

  • vcpkg install dbg-macro

2.3 With cmake

  • CMakeLists.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cmake_minimum_required(VERSION 3.11) # FetchContent added in cmake 3.11
project(app) # name of executable

set(CMAKE_CXX_STANDARD 17)

# dbg-macro
include(FetchContent)

FetchContent_Declare(dbg_macro GIT_REPOSITORY https://github.com/sharkdp/dbg-macro)
FetchContent_MakeAvailable(dbg_macro)

add_executable(${PROJECT_NAME} main.cpp) # your source files goes here
target_link_libraries(${PROJECT_NAME} PRIVATE dbg_macro) # make dbg.h available
  • main.cpp

006-Cpp webServer示例

Cpp webServer示例

1: 使用 c++11 标准库写一个 httpServer

  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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <thread>
#include <mutex>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define Server_Port  18080  // 服务listen端口

// 定义 HTTP 请求方法
enum class HttpMethod { GET, POST };

// HTTP 请求结构体
struct HttpRequest {
    HttpMethod method;
    std::string url;
    std::map<std::string, std::string> headers;
    std::string body;
};

// HTTP 响应结构体
struct HttpResponse {
    std::string status;
    std::map<std::string, std::string> headers;
    std::string body;
};

// 处理 HTTP 请求
// void handleRequest(const HttpRequest& req, int clientSocket) {
void handleRequest(int clientSocket) {
    HttpResponse res;
    // 构建 HTTP 响应
    res.status = "HTTP/1.1 200 OK";
    res.headers["Content-Type"] = "text/html";
    res.body = "<html><body><h1>Hello, World!</h1></body></html>";

    // 发送 HTTP 响应
    std::ostringstream oss;
    oss << res.status << "\r\n";
    for (const auto& header : res.headers) {
        oss << header.first << ": " << header.second << "\r\n";
    }
    oss << "Content-Length: " << res.body.length() << "\r\n";
    oss << "\r\n";
    oss << res.body;
    std::string response = oss.str();
    ssize_t n=write(clientSocket, response.c_str(), response.length()); // write用于将数据写入fd,返回值是成功写入的byte数
    if(n<0){
        std::cerr<<"Error writing response"<<std::endl;
    }else{
        std::cout<<"Bytes written :"<<n<<std::endl;
    }
    close(clientSocket);// 关闭客户端连接
}

// 启动 Web 服务器
void startWebServer() {
    int serverSocket, clientSocket;
    struct sockaddr_in serverAddr, clientAddr;
    socklen_t addrLen = sizeof(clientAddr);

    // 创建套接字
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == -1) {
        std::cerr << "Error creating socket" << std::endl;
        exit(1);
    }

    // 绑定地址和端口
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(Server_Port); // 监听端口
    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        std::cerr << "Error binding" << std::endl;
        close(serverSocket);
        exit(1);
    }

    // 监听连接
    if (listen(serverSocket, 10) == -1) {
        std::cerr << "Error listening" << std::endl;
        close(serverSocket);
        exit(1);
    }

    std::cout << "Web server started at http://localhost:"<<Server_Port << std::endl;

    while (true) {
        // 接受客户端连接
        clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &addrLen);
        if (clientSocket == -1) {
            std::cerr << "Error accepting connection" << std::endl;
            continue;
        }

        // 读取 HTTP 请求
        char buffer[1024];
        int bytesRead = read(clientSocket, buffer, sizeof(buffer));
        if (bytesRead <=0){
            std::cerr << "Error reading request" << std::endl;
            close(clientSocket);
            continue;
        }
        // 解析 HTTP 请求
        std::string requestString(buffer, bytesRead);
        std::istringstream iss(requestString);
        std::string line;
        HttpRequest req;
        if (std::getline(iss, line)) {
            std::istringstream issLine(line);
            std::string methodStr, url;
            issLine >> methodStr >> url;
            if (methodStr == "GET") {
                req.method = HttpMethod::GET;
            } else if (methodStr == "POST") {
                req.method = HttpMethod::POST;
            }
            req.url = url;
        }

        while (std::getline(iss, line)) {
            size_t colonPos = line.find(':');
            if (colonPos != std::string::npos) {
                std::string key = line.substr(0, colonPos);
                std::string value = line.substr(colonPos + 1);
                req.headers[key] = value;
            }
        }
        handleRequest(clientSocket); // 处理 HTTP 请求
    }
    // 关闭服务器套接字
    close(serverSocket);
}

int main() {
    startWebServer();
    return 0;
}

005-Cpp 动态内存分配函数

Cpp 动态内存分配函数

1: cpp 动态内存分配

  • void* malloc(unsigned int size);
  • void* realloc(void *ptr, unsigned int newsize);
  • void* calloc(size_t numElements, size_t sizeOfElement);
  • 加上一种new关键字,这四个都可以用来向内存申请空间

2: malloc

  • malloc(unsigned int size),它可以在内存的堆(Heap)区域申请连续大小为 size 个字节的空间,然后成功的话返回 void*指针(C/C++中,void*可以被强制转换为其他类型的指针,像 int*等等),这个指针是申请这段连续空间的首地址,如果申请失败的话就返回 NULL 指针。

3: calloc

  • calloc(unsigned int n, unsigned int size),它可以在内存的堆(Heap)区域申请连续 n 个空间,每个空间包含了 size 个字节的大小,也就是总共向内存申请了 n*size 个字节的空间大小,然后成功的话返回 void*指针(这列的也是可以被强制转换的),这个指针是申请这段连续空间的首地址,如果申请失败的话就返回 NULL 指针。

4: realloc

  • realloc(void *ptr, unsigned int newsize),这个的作用是向内存申请一个 newsize 的空间大小。当使用 malloc 申请的内存不够用的时候,就是用 realloc 来进行申请更大的空间,前面的指针 ptr 就是一开始用 malloc 申请所返回的指针。realloc 申请的方式是从内存堆的开始地址高地址查找一块区域,这块区域大于 newsize 的大小,申请成功后将原本的数据从开始到结束一起拷贝到新分配的内存区域,然后将原本 malloc 申请的区域释放掉(注意的是:原来的指针是自动释放的,不需要使用 free 来进行释放)。最后再这块区域的首地址返回。当内存不再使用时,要记得用 free()函数进行释放。

5: new

  • new是 C++提供的关键字,也是操作符,我们可以使用 new 在内存的堆上创建一个对象,在创建对象的时候,new 其实做了以下的操作:在堆上获得一块内存空间->调用构造函数(创建建档的类型变量时除外)->返回正确的指针;
  • char* p = new char(‘e’):分配1个char类型大小的内存空间;
  • char* p = new char[5]: 分配5个char类型大小的内存空间

6: demo.cpp

 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
#include <iostream>
#include <memory>
#include <cstring>
using namespace std;

/*
C++ 动态内存分配函数

- malloc 是 C/C++ 标准库中的函数,用于在堆上分配指定大小的内存空间,并返回指向该内存空间的指针。
在使用 malloc 分配内存后,需要手动调用 free 函数来释放这块内存空间,以防止内存泄漏。

- calloc 与 malloc 类似,也是用于在堆上分配内存空间的函数,但它会将分配到的内存空间初始化为零。
calloc 接受两个参数,分别是要分配的内存块的数量和每个内存块的大小。
与 malloc 一样,使用 calloc 分配的内存空间也需要通过调用 free 函数来释放。

- realloc 是用于重新分配内存空间大小的函数。它接受两个参数,一个是已经分配的内存空间的指针,
另一个是需要重新分配的内存空间的大小。
realloc 可以用于扩大或缩小已经分配的内存空间,如果新分配的内存空间大小大于原来的内存空间大小,
那么新分配的内存空间中未初始化的部分将保持未定义的值。与 malloc 和 calloc 一样,使用 realloc 分配的内存空间也需要通过调用 free 函数来释放

- new是C++提供的关键字,也是操作符,我们可以使用new在内存的堆上创建一个对象,在创建对象的时候,
new其实做了以下的操作:在堆上获得一块内存空间->调用构造函数(创建建档的类型变量时除外)->返回正确的指针

 */

//
void Malloc_Test(){
  char* ptr = (char*)malloc(20);                  // 向内存堆申请10个char类型的连续空间,并且返回首地址
  cout<<"malloc 指针变量的地址   :"<<&ptr<<endl;
  cout<<"malloc 申请到的空间首地址   :"<<static_cast<void*>(ptr)<<endl;
  strcpy(ptr,"malloc...lucas");                          // 如果你复制strcpy(ptr,"Servenssssssssssssssssssss");c程序就会中断,因为你申请的区域不够放了
  cout<<"malloc 申请到的空间赋值的地址:"<<static_cast<void*>(ptr)<<endl;
  free(ptr);
};

//
void Calloc_Test(){
  char* ptr=(char*)calloc(20,sizeof(char));           // 通过calloc申请10个char类型大小的内存空间
  cout<<"calloc 指针变量的地址   :"<<&ptr<<endl;
  cout<<"calloc 申请到的空间首地址时  :"<<static_cast<void*>(ptr)<<endl;
  strcpy(ptr,"calloc...lucas");
  cout<<"calloc 申请到的空间赋值的地址:"<<static_cast<void*>(ptr)<<endl;
//   cout<<"malloc 申请到的空间赋值的字符串:"<<strlen(ptr)<<endl;
  free(ptr);
};

void Realloc_Test(){
  char *ptr = (char*)malloc(6 * sizeof(char)); // 分配足够的内存来容纳 5 个字符和一个空终止符
  strcpy(ptr,"Serven"); // 将 6 个字符(包括空终止符)复制到分配的内存中
  cout<<"malloc 指针变量的地址   :"<<&ptr<<endl;
  cout<<"malloc 申请到的空间首地址时  :"<<static_cast<void*>(ptr)<<endl;

  char *ptru = (char*)realloc(ptr, 15 * sizeof(char)); // 分配足够的内存来容纳 14 个字符和一个空终止符
  strncpy(ptru,"Hello, Serven", 14); // 最多复制 14 个字符(包括空终止符)到分配的内存中
  ptru[14] = '\0'; // 手动添加空终止符以确保字符串正确终止
  cout<<"realloc 申请到的空间首地址时:"<<static_cast<void*>(ptru)<<endl;
  cout<<"realloc 申请到的空间赋值的字符串:"<<ptru<<endl;

  //free(ptr); // 无需释放 ptr,因为 realloc 会处理
  free(ptru);
}

int main(){
    cout<<"C++ 动态内存分配函数: malloc,calloc,realloc,new "<<endl;
    Malloc_Test();
    Calloc_Test();
    Realloc_Test();
    return 0;
}

7: 总结与比较

函数申请区域申请长度是否初始化头文件
mallocheapsizevoid*<stdlib.h>/<malloc.h>
callocheapn * sizevoid*<stdlib.h>/<malloc.h>
reallocheapnewsizevoid*
  • 如果申请调用成功,malloc()和 calloc()函数都会返回所分配的内存空间的首地址;
  • free()释放函数时紧跟着 malloc、calloc、realloc,因为它们都是返回 void*;而 new 使用的时 delete;
  • malloc 和 calloc 之间的区别就是:malloc 申请成功后没有初始化,这样会导致一些垃圾数据的存在,calloc 会初始化,将申请到的这一段连续空间初始化为 0,如果是实型数据的话,则会初始化为浮点数的 0;
  • malloc、calloc、realloc 三者都是返回 void*,C/C++支持强制转换 void*成其他类型的指针;
  • malloc 是在动态存储区域申请分配一块长度为 size 字节的连续区域,并返回这块区域的首地址;calloc 是在动态存储区域申请分配 n 块长度为 size 字节的区域,并返回这块区域的首地址;realloc 是将 ptr 内存大小增大到 newsize 个字节;
  • realloc 是从堆上分配内存,在扩大空间的时候会直接在现存的数据后面获得附加的字节,如果空间能够满足的话就扩展,如果不满足的话,那就从堆的开始地址开始寻找,找到第一个足够大的自由块,然后将现有的数据拷贝到新的位置,而老的那一块还是放到堆上。

01-云原生全景图

云原生全景图

1: 什么是云原生

2: 云原生发展

3: 云原生组成

3.1 不可变基础设施

3.2 微服务和服务网格

3.3 容器技术

3.4 DevOps

  • DevOps 是 Development 和 Operations 的组合词。它是一组过程、方法与系统的统称,用于促进开发(应用程序 / 软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。 DevOps全景图
  • CICD 持续集成 & 持续部署;

3.4.1 代码托管工具

  • Gitlab
  • Gitee
  • Github
  • 华为 CodeHub,阿里 Codeup,腾讯 Coding (企业级,收费)

3.4.2 集成流水线工具

  • 集成流水线就像传统的工业流水线一样,在经历构建、测试、交付之后,生产出一代一代更新迭代的软件版本。实现了软件产品小步迭代、高频发布、适时集成、稳定的系统演进线路图。在选择集成流水线工具的时候,我们需要关注:
    • 版本控制工具的支持;
    • 每个构建是否可以支持指定多个代码源 URLS;
    • 是否支持构建产物管理库,如公有云对象存储等;
    • 是否支持部署流水线,类似于一个或多个构建完成后触发另一个构建;
    • 是否支持并行构建;
    • 是否支持构建网格,以及对网格内机器管理的能力。如能否将多个构建同时分配到多个构建机器上执行,以提高执行速度;
    • 是否有良好的开放 API,比如触发构建 API、结果查询 API、标准的 Report 接口等;
    • 账户体系,是否支持第三方账户接入,如企业 LDAP 等;
    • 是否有良好的 Dashboard;
    • 多语言支持;
    • 与构建工具(如 Maven,Make,Rake,Nant、Node 等)和测试工具的集成

常用集成流水线工具

004-Cpp thread多线程用法整理

Cpp thread用法整理

1: Cpp thread 多线程

  • C++11 中加入了<thread>头文件,此头文件主要声明了std::thread线程类。C++11 的标准类std::thread对线程进行了封装,定义了 C++11 标准中的一些表示线程的类、用于互斥访问的类与方法等。

2: std::thread 类成员函数

  • get_id: 获取线程 ID,返回一个类型为 std:🧵:id 的对象;

03-C/Cpp常用头文件与库

C/Cpp常用头文件与库

1: C 头文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  include <assert.h>   //设定插入点
  include <ctype.h>    //字符处理
  include <errno.h>    //定义错误码
  include <float.h>    //浮点数处理
  include <fstream.h>  //文件输入/输出
  include <iomanip.h>  //参数化输入/输出
  include <iostream.h> //数据流输入/输出
  include <limits.h>   //定义各种数据类型最值常量
  include <locale.h>   //定义本地化函数
  include <math.h>     //定义数学函数
  include <stdio.h>    //定义输入/输出函数
  include <stdlib.h>   //定义杂项函数及内存分配函数
  #include <string.h>  //字符串处理
  include <strstrea.h> //基于数组的输入/输出
  include <time.h>     //定义关于时间的函数
  #include <wchar.h>   //宽字符处理及输入/输出
  include <wctype.h>   //宽字符分类//

2:Cpp 头文件

 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
include <algorithm>  //STL 通用算法
include <bitset>     //STL 位集容器
include <cctype>     //定义错误码
#include <cerrno>    //定义错误码
include <clocale>    //定义本地化函数
include <cmath>      //定义数学函数
include <complex>    //复数类
#include <cstdio>    /定义输入/输出函数
#include <cstdlib>   //定义杂项函数及内存分配函数
include <cstring>    //字符串处理
#include <ctime>     //定义关于时间的函数

include <deque>      //STL 双端队列容器

include <exception>  //异常处理类
include <fstream>    //文件输入/输出

include <functional> //STL 定义运算函数(代替运算符)

include <limits>     //定义各种数据类型最值常量

#include <list>      //STL 线性列表容器
#include <map>       //STL 映射容器
include <iomanip>
#include <ios>       //基本输入/输出支持
#include <iosfwd>    //输入/输出系统使用的前置声明
include <iostream>
include <istream>    //基本输入流
include <ostream>    //基本输出流
include <queue>      //STL 队列容器
include <set>        //STL 集合容器
#include <sstream>   //基于字符串的流
include <stack>      //STL 堆栈容器
include <stdexcept>  //标准异常类
include <streambuf>  //底层输入/输出支持
include <string>     //字符串类
include <utility>    //STL 通用模板类
include <vector>     //STL 动态数组容器
include <cwchar>
include <cwctype>

using namespace std;
///C99 增加
include <complex.h>  //复数处理
include <fenv.h>     //浮点环境
include <inttypes.h> //整数格式转换
include <stdbool.h>  //布尔环境
include <stdint.h>   //整型环境
include <tgmath.h>   //通用类型数学宏

3: STL 标准模板库

  • STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能;
  • STL 是一些容器、算法和其他一些组件的集合;

3.1 STL 的组成

STL 的组成含义其他
容器一些封装数据结构的模板类,例如 vector 向量容器、list 列表容器等-
算法STL 提供了非常多(大约 100 个)的数据结构算法,它们都被设计成一个个的模板函数,这些算法在 std 命名空间中定义,其中大部分算法都包含在头文件 中,少部分位于头文件 -
迭代器在 C++ STL 中,对容器中数据的读和写,是通过迭代器完成的-
函数对象如果一个类将 () 运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象(又称仿函数)-
适配器可以使一个类的接口(模板的参数)适配成用户指定的形式,从而让原本不能在一起工作的两个类工作在一起。值得一提的是,容器、迭代器和函数都有适配器-
内存分配器为容器类模板提供自定义的内存申请和释放功能,由于往往只有高级用户才有改变内存分配策略的需求,因此内存分配器对于一般用户来说,并不常用-

3.2 STL 头文件

  • 按照 C++ 标准库的规定,所有标准头文件都不再有扩展名。以 为例,此为无扩展名的形式,而 <vector.h> 为有扩展名的形式。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
include <iterator>
include <functional>
include <vector>
include <list>
include <queue>
include <deque>
include <stack>
include <set>
include <map>
include <algorithm>
include <numeric>
include <memory>
include <utility>

4: Cpp 库积累

  • xpack: 实现 C++ 结构体和 JSON/XML/BSON 互转的库
  • cpp-httplib: 一个只有头文件的 HTTP/HTTPS library。
  • wondertrader: 一站式的量化交易框架。这是采用 C++ 开发的一站式量化交易框架,支持量化交易过程中的数据清洗、回测分析、实盘交易、运营调度等环节。可用于多账户交易、极速/高频交易、算法交易等场景。