1 | package main |
1 | package main |
锁的引入是为了解决多线程处理共享资源的存取。Posix Thread提供一套mutex函数来处理互斥锁。互斥锁只有两种状态,上锁/解锁。当一个线程想要上锁一个已经上锁的互斥锁,则该线程就会挂起。A线程上锁了lock,B线程想要再次上锁lock。B线程挂起,直到A线程将lock解锁之后B线程才从挂起状态退出。
锁类型:
静态方式: 使用PTHREAD_MUTEX_INITIALIZER
宏
1 | pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
动态方式: pthread_mutex_init()
函数定义:
1 | int pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr); |
__mutexattr
用于指定互斥锁属性,NULL为缺省属性,通常使用NULL。
1 | int pthread_mutex_destroy (pthread_mutex_t *__mutex) |
要求锁处于解锁状态,否则返回EBUSY
。在Linux中锁不占用任何资源。
1 | int pthread_mutex_lock (pthread_mutex_t *__mutex); |
所有的锁都不可能被两个线程同时得到。
普通锁: 解锁者可以是同进程的任何线程。同一进程P,可以由A线程加锁一个普通锁,B线程解锁。
检错锁: 只有加锁者能解锁,否则返回EPERM。同一进程P,A线程加锁一个检错锁,B线程解锁该锁失败.
嵌套锁: 文档实现要求加锁者才能解锁,实验结果不一致?
解锁
1 | int pthread_mutex_unlock (pthread_mutex_t *__mutex); |
快速锁: 解除锁定。
递归锁:使锁上的引用计数-1。
检错锁: 解锁者和加锁者一致才解锁,否则啥也不做。
测试锁
1 | int pthread_mutex_trylock (pthread_mutex_t *__mutex); |
和pthread_mutex_lock
语义相同,锁被占用时不会阻塞挂起,返回EBUSY
属性:pthread_mutexattr_t mutexattr;
设置属性函数:pthread_mutexattr_settype(&mutexattr, kind);
类型:
PTHREAD_MUTEX_TIMED_NP
默认值,普通锁,快速锁。加锁之后,阻塞等待队列,解锁之后,阻塞队列中的先到的先得,有次序要求。普通锁容易死锁,线程A获得普通锁之后再次调用lock,A线程由于不能获得锁导致A挂起,进而导致死锁。
创建锁:
1 | pthread_mutex_t mutex; |
PTHREAD_MUTEX_RECURSIVE_NP
,嵌套锁.同一个线程可获得同一个锁多次,通过多次unlock解锁,使用计数机制。不同线程请求,加锁线程解锁时重新竞争,怎么理解,解锁只有公平竞争,没有先后区别。
PTHREAD_MUTEX_ERRORCHECK_NP
,检错锁。同一个线程请求同一个锁,返回EDEADLK。否则和PTHREAD_MUTEX_TIMED_NP
动作一致。保证多次加锁不不会死锁。线程在加锁后解锁前被取消,锁将永远处于锁定状态。需要在退出回调phtead_cleanup_push/pthread_cleanup_pop中解锁。
不应该在信号处理函数中使用互斥锁,容易造成死锁。
为了并发读不受影响,使用读写锁进行共享变量的处理。
1 | int pthread_rwlock_init(pthread_rwlock_t *rwlock,const pthread_rwlockattr_t *attr); |
可以多个线程使用读锁,并不会冲突。但是当某个线程想要写锁时,如果其他线程已经获得过读锁,就会进入阻塞状态,等读锁全部释放之后才能上写锁。这时候就像互斥锁了。
1 | static char share_data[20] = {"HelloWorld"}; |
运行结果:
1 | I locked read lock [140487461066496] |
读是可以被并发读的,但是写的话必须等待所有的读锁释放了才能写。
读写锁并不是所有的操作系统都支持的。不是POSIX标准。
1 | #include "stdbool.h" |
nat实现方式
特点:端口和IP不受限
有一个客户端C,使用8080端口提供服务。通过NAT转换之后的公网CIP:CPORT。这时候,有两个客户端A,B。它们都可以访问该ip和端口号。
graph LR NAT-->Client A-->|A IP:PORT,port1,port2....|NAT B-->|B IP:PORT,port1,port2....|NAT C-->|C IP:PORT,port1,port2....|NAT
特点:IP受限,端口不受限。
和FT类似,但是只有相互通讯过的IP才能通讯。
C和A有相互通讯过,不管端口是什么。路由已经存在。这时候A可以访问C的任意端口。但是B没有和A相互通讯过,B的请求不会被记录。
graph LR NAT -->Client A -->|port1,port2,port3...| NAT B-->|x|NAT C-->|x|NAT
特点:ip和端口都受限
比受限型NAT的多了一个端口限制。即相互信任,端口也对应起来。
graph LR NAT -->Client A -->|p1| NAT A -->|x p2| NAT B-->|x|NAT C-->|x|NAT
A可以使用p1端口进行通讯,不能使用p2端口通讯
每一个连接都是随机生成的端口号,严格要求双方的ip和端口。
graph LR ClientB-->NAT1 NAT1-->|A IP:PORT|A A-->|IP1:PORT1|NAT1 ClientB-->NAT2 NAT2-->|B IP:PORT|B B-->|IP2:PORT2|NAT2 ClientB-->NAT3 NAT3-->|C IP:PORT|C C-->|IP3:PORT3|NAT3
预判你生成地端口位置。
使用UPNP:变Symmetric NAT => Full Cone
有一个应用程序,需要执行不定量的协程数,要求主线程要等待各个协程全部完成之后退出
1.使用锁和协程计数器,主线程循环等待协程计数器为0,
2.使用waitGroup
1 | int main() { |
需求:想要批量注释代码
1 | int main() { |
注释掉代码:
1 | //int main() { |
操作命令:
1.Ctl+V进入块选
2.选择对应的列
3.Shit + a 进入插入模式
4.输入数据,位置和选块位置无关,只会从当前插入字符串的位置,往下复制。
5.按两次esc
1.normal模式输入qa,将操作的宏放入寄存器a。开始录制。
2.正常操作,记录命令,包括复制粘贴
3.normal模式输入q。接收宏录制。
4.normal模式输入@a,使用一次录制好的宏。100@a,执行100次录制的宏。
显示行号:set number
不显示行号:set nonumber
消息队列遥测传输协议(MQTT,Message Queuing Telemetry Transport), ISO标准(ISO/IEC PRF 20922)。
介绍
基于发布(Public)/订阅(Subscribe)范式的消息协议,
工作在TCP/IP协议族之上
为低性能远程设备和糟糕网络状况设计
两个网络实体:消息代理(message broker)与客户端(client).
三种身份:发布者(Publish)、代理(Broker)、订阅者(Subscribe)。
接收客户端的消息并转发到客户端,代理的角色(Broker),路由转发?那个客户端订阅了这个主题的消息,就把这个消息发给对应的客户端
多个客户端订阅同一个主题,收到相同消息的时间是一致的吗?换句话讲,消息代理是并行分发还是串行分发?
消息代理收到一个没有订阅者的消息,一般是丢弃掉,除了发布者标记为保留消息(retained message)
发送控制消息(Publish),携带主题信息。订阅特定的消息(Subscribe)。客户端不知道是谁订阅了这些消息,只管发布。
客户端只与消息代理进行连接,有多个代理。客户端与代理是一对多的吗?
客户端怎么保证消息到达了?想要同步操作怎么办?
控制消息最小只有2字节的数据(头部),最多256MB数据,14种预定消息类型用来:连接客户端与代理、断开连接、发布数据、确认数据接收、监督客户端与代理连接。
使用Last Will(遗言)和Testament(遗嘱)特性通知有关各方客户端异常中断的机制。
消息作为客户端和服务端通信的媒介,一个消息分成主题(Topic)和负载(Payload)两个部分
消息的类型,订阅者订阅了这个消息之后,就会收到这个Topic的Payload
消息的内容,真正的业务数据
MQTT会构造连接,建立客户端与服务器之间的连接,提供一个有序无损的、基于字节流的双向传输通道。有数据通过该通道时,会将Qos和Topic相连。
0.最多一次传送(只发,数据到没到不管)
1.至少一次传送(确认数据交付)
2.正好一次传送(保证数据交付成功)
问:1和2有什么大的区别吗?
数据到了和数据到了并收到回复了?
订阅包括主题筛选器(Topic Filter)和Qos。订阅和一个会话(Seesion)关联。一个会话会有多个订阅,每个订阅有不同的主题筛选器。我只订阅我感兴趣的内容。
客户端与服务端建立连接之后形成一个会话。
表示订阅到的感兴趣的内容,我执行订阅我感兴趣的内容,其他内容我并不关心。对主题名进行筛选。
https://github.com/1248/microcoap
编解码有bug,都依赖同一块内存。
可以肯定的是第一个字节的数据肯定是有的,第一个字节的数据一定要有。
针对第一个字节的数据进行解析,
前4个bit作为Delta,可以表示[0, 15]
后4个bit作为长度,[0,15]
规定是:delta的[13,15]作为保留值
4bit的无符号整数,[0,12]表示option值长度(byte),[13,15]保留做其他作用
注意:IV和Salt的大小为16,迭代次数可以自己定义
1 | package main |
1 |
|
使用golang构建Http请求
1 | requestBody := fmt.Sprintf("{\"jsonrpc\":\"2.0\",\"method\":\"aria2.tellStatus\",\"id\":\"QXJpYU5nXzE2MTY4NTg0ODZfMC44NzA1NzgxMzY4ODM5NjUz\", \"params\":[\"%s\"]}",gid) |
Https免认证证书
1 | client := http.Client{Transport: &http.Transport{ |
1 |
|
1 | package main |
从某个端口接收数据并从该端口返回数据
1 | var port = 1400 |
如果使用peerConn可以使用某个端口返回响应
1 | peerConn, err := net.DialUDP("udp4", &laddr , remoteAddr) |
使用golang起一个HTTP服务
1 | package main |
使用gin框架起一个http服务
1 | package main |
.key格式:私有的密钥
.csr格式:证书签名请求(证书请求文件),含有公钥信息,certificate signing request的缩写
.crt格式:证书文件,certificate的缩写
.crl格式:证书吊销列表,Certificate Revocation List的缩写
.pem格式:用于导出,导入证书时候的证书的格式,有证书开头,结尾的格式
生成CA私钥(.key)–>生成CA证书请求(.csr)–>自签名得到根证书(.crt)(CA给自已颁发的证书)。
1 | # Generate CA private key |
出现错误:
1 | Can't load ./.rnd into RNG 10504:error:2406F079:random number generator:RAND_load_file:Cannot open file:crypto\rand\randfile.c:98:Filename=./.rnd |
解决办法:
进入/etc/ssl/openssl.cnf
将下面的内容注释掉
1 | RANDFILE = $ENV::HOME/.rnd |
注释掉之后:
1 | #RANDFILE = $ENV::HOME/.rnd |
Common Name以外可以为空,Common Name必须为服务器的ip或域名
生成私钥(.key)–>生成证书请求(.csr)–>用CA根证书签名得到证书(.crt)
服务器端用户证书:
1 | # private key |
出现错误:
1 | Using configuration from /usr/lib/ssl/openssl.cnf |
新建文件夹demoCA/newcerts
,在文件夹demoCA
文件夹下新建
index.txt
文件,文件为空。serial
文件,写入01。
客户端用户证书:
1 | openssl genrsa -des3 -out client.key 1024 |
生成pem格式证书
有时需要用到pem格式的证书,可以用以下方式合并证书文件(crt)和私钥文件(key)来生成
1 | cat client.crt client.key> client.pem |
结果:
服务端证书:ca.crt, server.key, server.crt, server.pem
客户端证书:ca.crt, client.key, client.crt, client.pem
1 | # Generate server private key |
Https请求的时候会加入server.crt
,如果证书不对客户端会reset.
1 | -----BEGIN CERTIFICATE----- |
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true