东风草堂博客

公众号:开发者来风

Makefile 中=和:= 的区别

1
2
3
4
5
x = foo
y = $(x) bar
x = xyz
all:
@echo "$(y)"

执行make后,得到结果
xyz bar

1
2
3
4
5
x := foo
y := $(x) bar
x := xyz
all:
@echo "$(y)"

执行make后,得到结果
foo bar

阅读全文 »

无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
滑动窗口解法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> dic;
int i = -1, res = 0, len = s.size();
for(int j = 0; j < len; j++) {
if (dic.find(s[j]) != dic.end())
i = max(i, dic.find(s[j])->second); // 更新左指针
dic[s[j]] = j; // 哈希表记录
res = max(res, j - i); // 更新结果
}
return res;
}
};

动态规划解法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> dic;
int res = 0, tmp = 0, len = s.size(), i;
for(int j = 0; j < len; j++) {
if (dic.find(s[j]) == dic.end()) i = - 1;
else i = dic.find(s[j])->second; // 获取索引 i
dic[s[j]] = j; // 更新哈希表
tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
res = max(res, tmp); // max(dp[j - 1], dp[j])
}
return res;
}
};
阅读全文 »

分布式锁

多个服务竞争稀缺资源,需要使用分布式锁。

  • 锁是一种资源,需要存储,高可用性,避免锁全局失效。
  • 隐含条件:加锁和释放锁必须是同一个对象,需要记录持有锁的对象。
  • 另外需要实现互斥的语义,获取锁做个标记,释放锁时取消标记。
  • 获取锁和释放锁都是网络通信实现的,需要考虑锁超时的问题。
  • 锁释放通知问题:a.定时探寻。b. 被动通知(包括广播,和通知能够获取锁的特例)
  • 是否允许同一个对象多次获取锁,可重入锁

特性:互斥性、可重入性、锁超时(取到锁的进程可能会宕机)、高可用性(redis集群实现,哨兵模式和cluster模式都是异步复制、最终一致性,可能会丢数据,cluster集群lua脚本可能失效)、分类(公平锁:根据队列顺序获取锁、非公平锁:随机派发锁)
其中高可用可分为计算型和存储型,计算型的是无状态的,存储型需要有一致性的协议,主要包括选举主节点、数据复制。

实现方式:redis/mysql、zookeeper/etcd

阅读全文 »

以太网协议头:

ip协议头:

udp协议头:

tcp协议头:

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
#define ETH_ADDR_LEN 6

struct ethhder {
unsigned char dst_mac[ETH_ADDR_LEN];
unsigned char src_mac[ETH_ADDR_LEN];
unsigned short type; // 分为ip和arp
};

struct iphdr {
unsigned char version:4,
hdrlen:4; // 4*2^4=60, 最多60字节
unsigned char tos; // 以前的ip电话
unsigned short totlen; // 2^8 数据包的长度,最长65535,不同于MTU
unsigned short id;
unsigned short flag:3,
offset:13;
unsigned char ttl; // 默认64
unsigned char proto; // 包在盒子外面,指名里面上tcp/udp
unsigned short check;
unsigned int sip; // 地址在ip层
unsigned int dip;
};

struct udphdr {
unsigned char sport; // 端口在传输层
unsigned char dport;
unsigned char len;
unsigned char check;
};

struct udppkt {
struct ethhdr eh;
struct iphdr ip;
struct udphdr udp;
unsigned char payload[0]; // 柔性数组 sizeof 为0,内存池里面也有用
};

raw socket/netmap/dpdk/pf_ring/ebpf 可以从网络里面抓取完整的数据包,写完后用网络调试助手测试。

关键代码:

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
if (pfd.revents & POLLIN) {
unsigned char *stream = NULL;
nty_nic_read(ctx, &stream); // 读取原始数据
nty_eth_process(ctx, stream);
}

static int nty_eth_process(nty_nic_context *ctx, unsigned char *stream) {

struct ethhdr *eh = (struct ethhdr*)stream;

if (ntohs(eh->h_proto) == PROTO_IP) {
nty_ipv4_process(ctx, stream); // 分协议进行处理
} else if (ntohs(eh->h_proto) == PROTO_ARP) {
nty_arp_process(ctx, stream);
}

return 0;
}

int nty_ipv4_process(nty_nic_context *ctx, unsigned char *stream) {

struct iphdr *iph = (struct iphdr*)(stream + sizeof(struct ethhdr));
if (ip_fast_csum(iph, iph->ihl)) return -1;

if (iph->protocol == PROTO_UDP) {
nty_udp_process(ctx, stream); // udp处理
} else if (iph->protocol == PROTO_TCP) {
nty_tcp_process(ctx, stream);
} else if (iph->protocol == PROTO_ICMP) {
nty_icmp_process(ctx, stream);
}
return 0;
}

int nty_udp_process(nty_nic_context *ctx, unsigned char *stream) {
struct udppkt *udph = (struct udppkt *)stream;

int udp_length = ntohs(udph->udp.len);
udph->body[udp_length-8] = '\0';
struct udppkt udph_rt;
nty_udp_pkt(udph, &udph_rt); // 打包发送
nty_nic_write(ctx, &udph_rt, sizeof(struct udppkt)); // struct给了地址和大小就发送

return 0;
}

void nty_udp_pkt(struct udppkt *udp, struct udppkt *udp_rt) {
memcpy(udp_rt, udp, sizeof(struct udppkt));

memcpy(udp_rt->eh.h_dest, udp->eh.h_source, ETH_ALEN);
memcpy(udp_rt->eh.h_source, udp->eh.h_dest, ETH_ALEN);

memcpy(&udp_rt->ip.saddr, &udp->ip.daddr, sizeof(udp->ip.saddr));
memcpy(&udp_rt->ip.daddr, &udp->ip.saddr, sizeof(udp->ip.saddr));

memcpy(&udp_rt->udp.source, &udp->udp.dest, sizeof(udp->udp.source));
memcpy(&udp_rt->udp.dest, &udp->udp.source, sizeof(udp->udp.dest));
}

int nty_nic_write(nty_nic_context *ctx, const void *stream, int length) {
if (ctx == NULL) return -1;
if (stream == NULL) return -2;
if (length == 0) return 0;
nm_inject(ctx->nmr, stream, length); // 发送

return 0;
}
阅读全文 »

在 CMake 中,add_dependenciestarget_link_libraries 是两个不同的命令,用于不同的目的。

add_dependencies

add_dependencies 用于在目标之间建立构建依赖关系。它指定一个目标在另一个目标之前构建。

语法:

1
add_dependencies(target-name dependency-target1 [dependency-target2 ...])
阅读全文 »

都2022年了,再来谈谈拥有一个属于自己的留言板小程序的必要性,特别是想多和粉丝进行互动的号主朋友,为了增加与粉丝的粘性,为了让公众号变得有点灵性,还是有必要有一个自己的留言功能的,而且需要一个稳定可靠的留言功能。

没有留言功能,也不知道自己的文章写的好不好,得不到读者的反馈,渐渐的也就失去了坚持下去的动力,如果留言功能经常出问题,也会影响读者的体验,不知道的还以为公众号文章出问题了。

什么是留言小程序

首先要说明一下,留言板小程序是显示在文章末尾为小程序链接,需要引导读者点击进去进行留言的,并不是直接显示在文章末尾,那个只有微信原版的留言功能才能做到这样了。

界面是和微信原生基本保持一致的,功能上只会多不会少,可以回复留言、留言点赞、留言置顶、粉丝互动(即粉丝间可以互相留言),这些都是最基本的留言功能。

阅读全文 »

stl组成部分

容器、算法、迭代器、仿函数(函数对象),比如比较器、适配器、空间适配器(内存分配器)

容器

C++ 提供了多种标准容器。以下是 C++ 中常见的容器:
Array:静态数组,大小固定。
Vector:动态数组,支持随机访问和动态扩容。
List:双向链表,支持插入和删除操作。
Forward_list:单向链表,支持插入和删除操作。
Deque:双端队列,支持在队首和队尾进行插入和删除操作。
Stack:栈,支持基本的栈操作,先进后出。
Queue:队列,支持基本的队列操作,先进先出。
PriorityQueue:优先队列,支持按优先级插入和删除元素。
Set:集合,不允许重复元素,元素按一定的排序规则存储。
Map:映射,不允许重复的 key,元素按 key 的大小排序存储。
Unordered_set:哈希表实现的集合,不允许重复元素。
Unordered_map:哈希表实现的映射,不允许重复的 key。

迭代器的实现原理

阅读全文 »

职业评估

参考资料

官网:https://www.acs.org.au/
资料下载:https://www.acs.org.au/msa/information-for-applicants.html
帖子:https://www.oursteps.com.au/bbs/forum.php?mod=viewthread&tid=1551071
pdf合并:https://www.ilovepdf.com/
pdf压缩:https://www.ilovepdf.com/zh-cn/compress_pdf
naati: https://www.naati.com.au/、https://www.naati.com.au/online-directory/?require=translator&for=[607,757,1361]
状态查询:https://www.acs.org.au/msa/secure/applicant-dashboard.html

1
You will require 2 years relevant work experience completed within the past 10 years or 4 years relevant work experience completed anytime in your past work history (whichever provides the earliest skill date) to meet the suitability criteria.

如果在提交申请之前有任何疑问,请发送电子邮件至assessment@acs.org.au,技术移民团队的成员将能够协助解答。由于安全原因,我们无法在ACS办事处提供面对面的技能评估咨询。

阅读全文 »
0%