最近因为项目需求重新拾起了 C++,迁移到 x86_64 Linux 平台上之后 CMake 实在是一个必不可少的技能点,以下是一个分步教程,涵盖了CMake的常见构建系统用例,内容翻译自官网教程。

Step1 A Basic Starting Point

最基本的就是将一个源代码文件编译成一个可执行程序。对于一个简单的工程来说,两行的CMakeLists.txt文件就足够了。这将是我们教程的开始。CMakeLists.txt文件看起来会像这样:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cxx)

注意,在这个例子中,CMakeLists.txt都是使用的小写字母。事实上,CMake命令是大小写不敏感的,你可以用大写,也可以用小写,也可以混写。tutorial.cxx源码会计算出一个数的平方根。它的第一个版本看起来非常简单,如下:

Continue reading

linux 下 g++ 编译程序时,-I, -L, -l 的作用

g++ -o compress  compress.cpp  \
  -I/home/include/ \
  -L/lib/ \
  -lz

1. -I (Capital i)

编译程序按照 -I 指定的路进去搜索头文件。

-I/home/include/ 表示将 -I/home/include/ 目录作为第一个寻找头文件的目录,寻找的顺序是:
/home/include/ –>/usr/include–>/usr/local/include

2. -L

表示:编译程序按照 -L 指定的路进去寻找库文件,一般的在 -L 的后面可以一次用 -l 指定多个库文件。

-L/lib/ 表示到 /lib/ 目录下找库文件

3. -l (lowercase L)

表示:编译程序到系统默认路进搜索,如果找不到,到当前目录,如果当前目录找不到,则到 $LD_LIBRARY_PATH 等环境变量置顶的路进去查找,如果还找不到,那么编译程序提示找不到库。

本例子使用的是gunzip库,库文件名是libz.so,库名是z。很容易看出,把库文件名的头lib和尾.so去掉就是库名了。

通过 git clone 命令默认拉取的是 git repo master 分支代码。

git clone git@git.kangkai.art:xxx/xxx.git

如果需要拉取非 master 分支则需要如下操作。

Solution

  1. 查看远程分支
git branch -r
  1. 查看所有分支
git branch -a 

* master
  henry-dev
  transform_face_attr
  remotes/origin/henry-dev
  remotes/origin/master
  remotes/origin/transform_face_attr
  1. 切换并拉取 henry-dev 分支
git checkout origin/henry-dev
  1. Done!

Classic Solution

传统的方法则是创建一个新的本地分支并指向远程分支,或者想要修改正在跟踪的上游分支。

  1. 我们首先需要在本地先建立一个分支,建议名称和远程的想要同步的分支名称一样
git branch henry-dev
  1. 切换到新建的本地分支
git checkout henry-dev
# Switched to branch 'henry-dev'
  1. 接下来需要建立上游分支的关联
git branch --set-upstream-to=origin/henry-dev henry-dev
# Branch henry-dev set up to track remote branch henry-dev from origin.
  1. 拉取该远端分支的最新代码
git pull
  1. Done!

四种常见的 POST 提交数据方式

HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中 POST 一般用来向服务端提交数据,本文主要讨论 POST 提交数据的几种方式。

我们知道,HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三个部分:状态行、请求头、消息主体。类似于下面这样:

<method> <request-URL> <version>
<headers>

<entity-body>

协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式。实际上,开发者完全可以自己决定消息主体的格式,只要最后发送的 HTTP 请求满足上面的格式就可以。

但是,数据发送出去,还要服务端解析成功才有意义。一般服务端语言如 php、python 等,以及它们的 framework,都内置了自动解析常见数据格式的功能。服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。下面就正式开始介绍它们。
Continue reading

最近听了 IoT 长连接 Erlang 研发同学的技术分享,部分分享内容涉及到到了 HTTP/2,刚好在草稿箱里翻到了两年前攒的这篇文章,趁这个机会补充一下把他放出来吧。

HTTP/2 不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。

0x00 HTTP Frames

HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为”帧”(frame):头信息帧和数据帧。

HTTP/2 相较于 HTTP/1.* 的不同点在于,HTTP/2 将 HTTP 协议通信分解为二进制编码Frame的交换,这些Frame对应着特定Stream中的Message。所有这些都在一个 TCP 连接内复用。这是 HTTP/2 协议所有其他功能和性能优化的基础。

二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。

Frame 的基础结构由五部分组成:

  • Length: 表示 Frame Payload 的大小,是一个 24-bit 的整型,表明 Frame Payload 的大小不应该超过 2^24 – 1 byte,但其实 payload 默认的大小是不超过 2^14 byte,可以通过 SETTING Frame 来设置 SETTINGS_MAX_FRAME_SIZE 修改允许的 Payload 大小;
  • Type: 表示 Frame 的类型,目前定义了 0-9 共 10 种类型;
  • Flags: 为一些特定类型的 Frame 预留的标志位,比如 Header, Data, Setting, Ping 等,都会用到;
  • R: 1-bit 的保留位,目前没用,值必须为 0;
  • Stream Identifier: Steam 的 id 标识,表明 id 的范围只能为 0 到 2^31 – 1 之间,其中 0 用来传输控制信息,比如 Setting, Ping;客户端发起的 Stream id 必须为奇数,服务端发起的 Stream id 必须为偶数;并且每次建立新 Stream 的时候,id 必须比上一次的建立的 Stream 的 id 大;当在一个连接里,如果无限建立 Stream,最后 id 大于 2^31 时,必须从新建立 TCP 连接,来发送请求。如果是服务端的 Stream id 超过上限,需要对客户端发送一个 GOWAY 的 Frame 来强制客户端重新发起连接。

Continue reading

我维护的一套线上代码需要更换到另外一个 Git repo,我打算直接将线上运行的 latested release 代码直接合并到新 repo,但是又不想手动处理合并差异,只想简单粗暴将代码推送到远端,

git push --force origin

有时候,需要恢复到 commit head, 或者手误提交了错误的 commit, 但是还没有 push 到远端,这时也是可以撤销的,

git reset --hard

只回退 commit, 不恢复 index file:

git reset --soft

今天早上家里的网络全线瘫痪,没时间多搞就赶紧出去学习去了,晚上查了好久也没查出原因,于是干脆reset了机器,这些配置文件又得重新填QAQ

因为毕设用到一堆硬件设备,都是无线接在openwrt和树莓派下的,尽管家里路由器的DHCP租期设置的很长,但是为了高可靠性,还是把mac与IP绑定会比较好,实现方法有如下两种。

Solution I:

修改/etc/config/dhcp,增加如下的内容:

config host
option ip ‘192.168.1.2’
option mac ’00:11:22:33:44:55′
option name ‘mypc’

Solution II:

dnsmasq读取 /etc/ether

/etc/init.d/dnsmasq -> option readethers 1

在/etc/ether中增加如下内容即可实现mac地址与IP地址的绑定

# mac ip
11:22:33:44:55:66 192.168.1.3
00:1c:cc:83:d9:2a 192.168.1.164

最后还需要重启dnsmasq

/etc/init.d/dnsmasq restart

如果需要绑定IP的设备之前一直处于连接到路由器的状态,需要断开连接后再次连接路由器才可以获得所设置的绑定的地址。

Note: 本文成立的充要条件是我能找到一个女朋友

早上我出门去上班了,我的小女朋友还在家里认真读书,读累了再顺便帮我做点好吃的.  但是她经常会因为沉迷学习而忘了喝水.

我是一个生活作息很不规律的人,这就导致了租房决不能离开公司方圆3km的范围之外,因为我早上起不来.

尽管我自诩是一个multitasking的男人,在每天早上三个核桃的滋补下记忆力也还行,但是如果我忘记了一系列和女友相关的Anniversaries,根据超弦理论,那么我写的这篇文章就不会存在了.

感谢DK那篇“Behavior patterns between relationships”,让我想到是不是可以把家里闲置的那块树莓派利用起来,有事没事多给我女朋友说说好话,每隔四十分钟提醒她休息一下,每隔一个多小时提醒她喝水,没到晚上了提醒她给我做饭。。或者等我回来做也行,扯远了

Continue reading

Environment Setup

Steps to reproduce

Logs/Trace

Note: If you get a browser JS error please run npm run dev. This will provide source maps and a much more useful stack trace.

events.js:160
throw er; // Unhandled ‘error’ event
^

Error: listen EADDRINUSE :::8888
at Object.exports._errnoException (util.js:1022:11)
at exports._exceptionWithHostPort (util.js:1045:20)
at Server._listen2 (net.js:1262:14)
at listen (net.js:1298:10)
at Server.listen (net.js:1376:9)
at Object.<anonymous> (/code/server.js:12:4)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)


Solution:

That error means I’m already running something else on port 8888, I changed 8888 in my code to 8899 that I’ve used before that I knew was open and all is well.