4. 源码管理系统
- 目标
- 了解源码管理
- 了解源码管理的工具
- 了解源码管理流程
- 了解git源码管理的分支
4.1. 源码管理简述
在现代软件开发项目中,要成为一个有效的软件开发人员,我们必须能够与其他项目贡献者并行进行开发。
源代码管理(SCM)系统不是什么新思想。为了编写一些能够更快速、简单地开发以后软件项目的软件,已经进行了很多尝试。
最新的源代码解决方案都包含了版本控制系统,它可以对源代码的修改进行回滚,从而将有害的代码剔除出项目之外,或者简单地跟踪哪些人修改了代码的哪些行的内容。版本控制系统试图解决开发人员在试图同时对某个文件进行修改时所出现的冲突问题,可以防止用户覆盖其他人所作的修改。源代码管理使用的很多流行解决方案都试图解决以前 SCM 解决方案中的失效问题。
集中化的版本控制系统通常采用两种方式:
- 有些提供了文件锁来防止多个用户的并行访问。这些系统对文件进行加锁,这样在某个时间只有一个开发人员对中心仓库具有写入权限。
- 另外一些工具,例如 CVS,允许多个开发人员同时对相同的文件进行编辑,并提供了一些机制稍后合并这些修改。
流行的版本控制系统包括:
- CVS
- Subversion
- Arch
- Bazaar
- BitKeeper
4.2. Git
4.2.1. 什么是 Git?
非常简单地说,Git 是 Linus Torvalds 最近实现的源代码管理软件。正如所提供的文档中说的一样,“Git 是一个快速、可扩展的分布式版本控制系统,它具有极为丰富的命令集,对内部系统提供了高级操作和完全访问。”
Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper,后者之前一直是 Linux 内核开发人员在全球使用的主要源代码工具。开放源码社区中的有些人觉得 BitKeeper 的许可证并不适合开放源码社区的工作,因此 Torvalds 决定着手研究许可证更为灵活的版本控制系统。尽管最初 Git 的开发是为了辅助 Linux 内核开发的过程,但是我们已经发现在很多其他自由软件项目中也使用了 Git。例如,X.org 最近就迁移到 Git 上来了,很多 Freedesktop.org 的项目也迁移到了 Git 上。
Git 目前主要由寻找 CVS 或专有代码管理解决方案替代物的软件开发人员所使用。Git 与 CVS 有很多区别:
- 分支更快、更容易。
- 支持离线工作;本地提交可以稍后提交到服务器上。
- Git 提交都是原子的,且是整个项目范围的,而不像 CVS 中一样是对每个文件的。
- Git 中的每个工作树都包含一个具有完整项目历史的仓库。
- 没有哪一个 Git 仓库会天生比其他仓库更重要。
4.3. Git源码管理的中的流程
- 源码复制和传播
- 源代码向研发部门以外复制必须获得”总经理“的书面授权。并必需记录复制人、批准人、复制时间、复制目的、文件流向、文件版本或内容。
- 源代码的借阅、复制必须进行详细的登记,必需记录借阅人、批准人、借阅时间、借阅目的、文件流向、文件版本或内容、归还时间。
- 对于因合作需要,需要向外复制、传播、分发源代码的,不论是全部还是部分代码和资料,均必需和对方签订技术、源码的保密协定,明确对方应当承担的对源码保密的责任和义务。
-
源码的版本管理
- 版本号:由“<主版本号>.<次版本号>.<修订号>”三段组成,中间是点号分开。
-
源码的提交管理
- 源码修改完成后,提交到”非主分支“, 分支命名可关联bug编号(建议)
- 提交源码评审, 一般评审人员具有一票否决。
- 评审通过后,提交源码merge申请,
- 专人(配置管理员)或源码的Maintainer负责合并
4.4. 成功的Git分趾模型
4.4.1. 主要分支
在核心上,开发模式受到现有模型的极大启发。中央回购拥有两个主要的分支,无限生命:
- 主分支
- master
- 开发分支
- develop
- 发布分支
- release-* 每个Git用户应该熟悉该master分支origin。与master分支并行,存在另一个分支develop。
我们认为origin/master是源代码HEAD总是反映生产就绪状态的主要分支 。
我们认为origin/develop是主要的分支,源代码 HEAD总是反映出下一个版本的最新交付发展变化的状态。有人会称之为“整合分支”。这是每个自动夜间建造的地方。
当develop分支中的源代码达到稳定点并准备释放时,所有这些更改都应该以master 某种方式合并,然后用发布号标记。将详细讨论如何做到这一点。
因此,每次将更改合并到一起时master,根据定义,这是一个新的生产版本。我们往往对此非常严格,所以理论上,我们可以使用Git钩子脚本在每次提交时自动构建和推出我们的软件到我们的生产服务器 master。
5. pcap文件解析
- 目标
- 了解 使用tcpdump生成pcap文件的方式
- 掌握 使用wireshark生成pcap文件的方式
- 掌握 pcap文件的格式,
- 应用编码会解析pcap文件
5.1. 获取pcap文件
5.1.1. pcap是什么
pcap是一种数据流格式,wireshark软件可以直接把网络数据流变成这种格式。
在Linux里,pcap可以说是一种通用的数据流格式,很多开源的项目都需要用到这种格式的文件。
5.1.2. 如何获取 pcap文件
一般通过tcpdump或者 wireshark工具获取pcap文件。
-
使用tcpdump命令获取pcap文件
-
tcpdump基本用法
tcpdump [ -i interface ] [ -w file ] [ expression ]
- -i : 监听 interface. 如果 不指定 接口, tcpdump 在 系统 的 接口 清单 中, 寻找 号码最小, 已经 配置好的 接口 (loopback 除外)
- -w 把 原始报文 存进 file, 不做 分析 和 显示. 它们 可以 以后 用 -r 选项 显示. 如果 file 是 -'', 就 写往 标准输出.
- -v (稍微多一点) 繁琐的输出. 例如, 显示 IP 数据报 中的 生存周期 和 服务类型.
- -vv 更繁琐的输出. 例如, 显示 NFS 应答报文 的 附加域.
Panda.Guo@2018-07-26 20:56:13 $ sudo tcpdump -i wlp2s0 -w ~/wl.pcap -vv
tcpdump: listening on wlp2s0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C69 packets captured
69 packets received by filter
0 packets dropped by kernel
Panda.Guo@2018-07-26 20:56:51 $
通过Ctrl+c
随时选择终止。
-
使用wireshark工具抓取pcap文件
- 启动 wireshark,
- 选择 “接口”后, 点击“开始捕获分组” 按钮,开始抓包
- 。。。。
- 选择 “停止捕获分组”
- 选择“文件”-> "保存", 弹出对话框,如下图所示
-
-
- 在1位置,输入pcap文件名称
- 在2位置, 选则pcap类型。
-
5.2. pcap文件格式
5.2.1. pcap格式
上图是pcap的格式结构图,分成两大部分:
-
Global Header (共 24 Byte)整个数据流文件,只会有一个 Global Header,它定义了本文件的读取规则、最大储存长度限制等内容;
-
- Magic:4Byte:标记文件开始,并用来识别文件自己和字节顺序。0xa1b2c3d4用来表示按照原来的顺序读取,0xd4c3b2a1表示下面的字节都要交换顺序读取。考虑到计算机内存的存储结构,一般会采用0xd4c3b2a1,即所有字节都需要交换顺序读取。
- Major:2Byte: 当前文件主要的版本号,一般为 0x0200【实际上因为需要交换读取顺序,所以计算机看到的应该是 0x0002】
- Minor:2Byte: 当前文件次要的版本号,一般为 0x0400【计算机看到的应该是 0x0004】
- ThisZone:4Byte:当地的标准时间,如果用的是GMT则全零,一般都直接写 0000 0000
- SigFigs:4Byte:时间戳的精度,设置为 全零 即可
- SnapLen:4Byte:最大的存储长度,如果想把整个包抓下来,设置为 ffff 0000,但一般来说 ff7f 0000就足够了【计算机看到的应该是 0000 ff7f 】
- LinkType:4Byte:链路类型,常用类型有以下几种,其他的,需要用的时候再查就行了。
- 0 BSD loopback devices, except for later OpenBSD
- 1 Ethernet, and Linux loopback devices
- 6 802.5 Token Ring
- 7 ARCnet
- 8 SLIP
- 9 PPP
- 10 FDDI
- 100 LLC/SNAP-encapsulated ATM
- 101 "raw IP", with no link
- 102 BSD/OS SLIP
- 103 BSD/OS PPP
- 104 Cisco HDLC
- 105 802.11
- 108 later OpenBSD loopback devices (with the AF_value in network byte order)
- 113 special Linux "cooked" capture
- 114 LocalTalk
-
Packet Header(共 16 Byte) Packet Header可以有多个,每个Packet Header后面会跟着一串Packet Data,Packet Header定义了Packet Data的长度、时间戳等信息。
-
- Timestamp:被捕获时间的高位,单位是seconds
- Timestamp:被捕获时间的低位,单位是microseconds
-
Caplen: 数据包长度:32位 ,标识所抓获的数据包保存在pcap文件中的实际长度,以字节为单位。
- a 32-bit value giving the number of bytes of packet data that were captured;
-
Len:数据包实际长度: 所抓获的数据包的真实长度,如果文件中保存不是完整的数据包,那么这个值可能要比前面的数据包长度的值大。
- a 32-bit value giving the actual length of the packet, in bytes (which may be greater than the previous number, if you are not saving the entire packet).
-
Packet Data(共 Caplen Byte)在包头之后,就是数据包的数据了,数据长度就是Caplen个Byte,
- 在这之后就是一个新的Packet Header,定义一个新的Packet Data属性,再接一个新的Packet Data,如此循环。
- PCAP文件里面并没有规定捕获的Packet数据包之间有什么间隔字符串,下一组数据在文件中的起始位置。我们需要靠第一个Packet包确定
5.2.2. 实例剖析
Panda.Guo@2018-06-26 20:01:00 $ hd ~/wl.pcap | less
00000000 d4 c3 b2 a1 02 00 04 00 00 00 00 00 00 00 00 00 |................|
00000010 00 00 04 00 01 00 00 00 08 d9 28 5a 85 ba 0b 00 |..........(Z....|
00000020 3c 00 00 00 3c 00 00 00 50 9a 4c 20 65 dc dc fe |<...<...P.L e...|
00000030 18 2a d5 c9 08 00 45 00 00 28 13 de 40 00 75 06 |.*....E..(..@.u.|
00000040 7b f6 ca 59 e9 64 c0 a8 01 95 01 bb 15 bd 47 26 |{..Y.d........G&|
00000050 64 57 1b f9 dd fc 50 10 03 fe 78 ef 00 00 00 00 |dW....P...x.....|
00000060 01 95 01 bb 08 d9 28 5a 85 ba 0b 00 4b 01 00 00 |......(Z....K...|
00000070 4b 01 00 00 50 9a 4c 20 65 dc dc fe 18 2a d5 c9 |K...P.L e....*..|
00000080 08 00 45 00 01 3d 13 df 40 00 75 06 7a e0 ca 59 |..E..=..@.u.z..Y|
00000090 e9 64 c0 a8 01 95 01 bb 15 bd 47 26 64 57 1b f9 |.d........G&dW..|
000000a0 dd fc 50 18 03 fe 98 00 00 00 17 03 02 01 10 3c |..P............<|
000000b0 c4 c4 aa 39 d0 30 29 66 3e e5 2d 2d 39 60 64 ed |...9.0)f>.--9`d.|
.....
5.3. pcap 文件解析关键代码
示例代码如下:
函数名称:pcap_t *pcap_open_offline(char *fname, char *ebuf)
函数功能:打开以前保存捕获数据包的文件,用于读取。
参数说明:fname参数指定打开的文件名。该文件中的数据格式与tcpdump和tcpslice兼容。”-“为标准输入。ebuf参数则仅在pcap_open_offline()函数出错返回NULL时用于传递错误消息。函数名称:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user)
函数功能: 捕获并处理数据包。此函数在cnt个数据包被处理或出现错误时才返回,但读取超时不会返回。。cnt参数为负值时pcap_loop()函数将始终循环运行,除非出现错误。函数名称:void pcap_close(pcap_t *p)
函数功能:关闭p参数相应的文件,并释放资源。
对于 pcap_loop:
pcap_loop原型是pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user)其中第一个参数是pcap_open_offline返回的句柄,第二个是指定捕获的数据包个数,如果为-1则无限循环捕获。第四个参数user是留给用户使用的。第三个是回调函数其原型如下:pcap_callback(u_char* argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)其中参数pcap_content表示的捕获到的数据包的内容参数argument是从函数pcap_loop()传递过来的。注意:这里的参数就是指 pcap_loop中的 *user 参数参数pcap_pkthdr 表示捕获到的数据包基本信息,包括时间,长度等信息.另外:回调函数必须是全局函数或静态函数,其参数默认,比如pcap_loop()可以写成pcap_loop(pcap_handle,10,pcap_callback,NULL)不能往里面传递实参.
pcap_loop和callback之间参数存在联系:pcap_loop的最后一个参数user是留给用户使用的,当callback被调用的时候这个值会传递给callback的第一个参数(也叫user),callback的最后一个参数p指向一块内存空间,这个空间中存放的就是pcap_loop抓到的数据包。callback的第二个参数是一个结构体指针,该结构体定义如下:// /usr/include/pcap/pcap.hstruct pcap_pkthdr {struct timeval ts; /* 时间戳 */bpf_u_int32 caplen; /* 已捕获部分的长度 */bpf_u_int32 len; /* 该包的脱机长度 */
};这个结构体是由pcap_loop自己填充的,用来取得一些关于数据包的信息所以,在callback函数当中只有第一个user指针是可以留给用户使用的,如果你想给callback传递自己参数,那就只能通过pcap_loop的最后一个参数user来实现了