Go语言项目标准结构应该如何组织的?
这里写自定义目录标题
- Go项目本身的目录结构
- Go语言项目典型目录结构
- GO语言项目最小标准目录结构
- 可执行的Go语言项目目录结构
- 库的Go语言项目目录结构
- 关于`internal`目录
- 总结
- 参考文章
每当我们写一个非hello world实用程序的Go程序或库时,我们都会在项目结构、代码风格和标识符命名这三个“门槛”面前折腾很久,甚至得不到满意的答案。
在本文中,我们将详细介绍如何跨过Go项目结构的“门槛”,帮助您更快地进入Go语言的核心腹地,提高学习效率。
除非是像hello world这样简单的程序,否则每当我们写实用程序或库时,都会遇到使用什么项目结构的问题(通常一个Go项目对应一个repository)。在Go中,项目结构也很重要,因为它决定了项目内部包的布局和包依赖关系,也影响了外部项目对项目内包的依赖和引用。
Go项目本身的目录结构
我们来看看Go语言本身的项目结构,世界上第一个Go项目。
Go项目的项目结构从1.0版本发布开始就非常稳定,Go项目的顶层结构至今基本没有变化。截至go project commit 1e3ffb0c (2019.5.14),go项目结构如下。
$ tree -LF 1 ~/go/src/github.com/golang/go
./go
├── api/
├── AUTHORS
├── CONTRIBUTING.md
├── CONTRIBUTORS
├── doc/
├── favicon.ico
├── lib/
├── LICENSE
├── misc/
├── PATENTS
├── README.md
├── robots.txt
├── src/
└── test/
作为Go的“创始项目”,其项目结构布局对后续其他Go项目具有重要参考意义,尤其是早期Go项目中src目录下的结构,被Go社区广泛用作模板Go 应用程序项目结构。我们以早期Go 1.3版本的src目录下的结构为例。
$ tree -LF 1 ./src
./src
├── all.bash*
├── all.bat
├── all.rc*
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── lib9/
├── libbio/
├── liblink/
├── make.bash*
├── make.bat
├── Make.dist
├── make.rc*
├── nacltest.bash*
├── pkg/
├── race.bash*
├── race.bat
├── run.bash*
├── run.bat
├── run.rc*
└── sudo.bash*
关于上面src目录下面的结构,我总结了三个特点。
-
代码构建的脚本源文件放在src下的顶层目录下。
-
src 下的二级目录 cmd 存放了 go 工具链相关的可执行文件(如:go、gofmt 等)及其主要包源文件的主目录。
$ tree -LF 1 ./cmd
./cmd
...
├── 6a/
├── 6c/
├── 6g/
...
├── cc/
├── cgo/
├── dist/
├── fix/
├── gc/
├── go/
├── gofmt/
├── ld/
├── nm/
├── objdump/
├── pack/
└── yacc/
- src下的二级目录,pkg,存放着上面cmd下各个工具链所依赖的packages、go runtime、go standard library的源文件。
$ tree -LF 1 ./pkg
./pkg
...
├── flag/
├── fmt/
├── go/
├── io/
├── log/
├── math/
...
├── syscall/
├── testing/
├── text/
├── time/
├── unicode/
└── unsafe/
从 Go 1.3 版本至今,Go 项目下的 src 目录发生了一些结构上的变化。
- Go 1.4 从 Go 源代码树中的 src/pkg/xxx 中删除了 pkg 级别,而是直接使用 src/xxx。
- Go 1.4 在 src 下增加了 internal 目录,用来存放不能外部导入的,只供 Go 项目使用的包。
- Go 1.6 在 src 下增加了 vendor 目录,但是 Go 项目本身真正启用了 Go 1.7 中的 vendor 机制。vendor目录下存放着Go项目自身对外部项目的依赖,主要是golang.org/x下的包,包括:net、text、crypto等。该目录下的包随着每个Go版本的发布而更新。
- Go 1.13版本在src下增加了go.mod和go.num,实现了go项目本身go module的迁移。go项目中的所有包都放在了std模块下,其依赖仍然是golang.org/x下的各种包
// Go 1.13版本go项目src下面的go.mod
module stdgo 1.12require (golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7golang.org/x/sys v0.0.0-20190529130038-5219a1e1c5f8 // indirectgolang.org/x/text v0.3.2 // indirect
)
这是最新 Go 1.16 版本的 src 目录中的完整布局。
├── Make.dist
├── README.vendor
├── all.bash*
├── all.bat
├── all.rc*
├── bootstrap.bash*
├── buildall.bash*
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── cmp.bash
├── go.mod
├── go.sum
├── internal/
├── make.bash*
├── make.bat
├── make.rc*
├── race.bash*
├── race.bat
├── run.bash*
├── run.bat
├── run.rc*
├── testdata/
...
└── vendor/
Go语言项目典型目录结构
GO语言项目最小标准目录结构
一个Go应用项目结构的标准布局是什么样子的,Go官方团队从来没有给出过一个参考标准。不过,作为Go语言项目的技术负责人, Russ Cox在开源项目的一期中给出了他对Go项目结构最小标准布局的思考。他认为Go项目的最低标准布局应该如下。
// 在Go项目仓库根路径下- go.mod
- LICENSE
- xx.go
- yy.go
...or- go.mod
- LICENSE
- package1- package1.go
- package2- package2.go
...
至于 pkg、cmd、docs,这些目录不应该是 Go 项目的标准结构的一部分,或者至少不需要。相信 Russ Cox 给出的最小标准布局与 Go 的“简单”哲学是一致的,足够灵活,可以满足各种 Go 项目的需求。
然而,在 Russ Cox 详细阐述最低标准之前,Go 社区处于“非标准”状态,早期 Go 语言自身的项目结构对现有大量 Go 开源项目的影响依然持久。对于更大的 Go 应用程序,我们势必会扩展“最小标准布局”。这个扩展显然不会盲目,但还是会参考Go语言项目自身的结构布局,所以我们有以下非官方标准建议的结构布局。
可执行的Go语言项目目录结构
基于Go语言项目本身的早期结构及其后续演变,Go社区经过多年的Go语言实践积累,逐渐形成了符合Russ Cox最小标准布局的典型项目结构,如下图所示。
以上是一个典型的支持构建二进制可执行文件的Go项目结构(在cmd下),我们分别看一下各个重要目录的用途。
-
cmd目录:存放项目要编译构建的可执行文件对应的主包源文件。如果有多个可执行文件要构建,则每个可执行文件的主包放在单独的子目录下,如图中的app1和app2;cmd目录下每个app的主包,将整个项目的依赖连接在一起;而且一般来说,主包应该是非常简洁的。我们会在main包中做一些命令行参数解析、资源初始化、日志工具初始化、数据库连接初始化等,之后我们会将程序的执行权交给更高级的执行控制对象;也有一些go项目把cmd的名字改成了app,但是它的实用性并没有改变。
-
pkg目录:项目本身要用到的,也是主包对应的可执行文件依赖的库文件;同时,该目录下的包也可以被外部项目引用,作为项目导出包的“聚合”;也有一些项目会 pkg 名称为 lib,但目录用途保持不变;因为Go语言项目在1.4版本去掉了pkg目录,所以有一些项目直接把包放在项目的根路径下,但是我觉得对于一些比较大的项目,包太多会成为顶层目录该项目不够简洁和“拥挤”。对于复杂的 Go 项目,我建议保留 pkg 目录。
-
Makefile:这里的Makefile是项目构建工具使用的脚本的“代表”,它可以代表任何第三方构建工具使用的脚本。对于大型项目来说似乎是必不可少的。在一个典型的Go项目中,项目构建工具的脚本通常放在项目的顶层目录下,比如这里的Makefile;对于构建脚本较多的项目,也可以创建构建目录,将构建脚本的规则属性文件和子构建脚本放入其中。
-
go.mod和go.sum:用于Go语言包依赖管理的配置文件。Go 1.11 引入了 go modules,go module 在 Go 1.16 成为了默认的依赖包管理和构建机制。所以对于新的 Go 项目,我们推荐使用 go modules 来进行包依赖管理。对于没有使用go modules进行包管理的项目(可能主要是使用go 1.11以前版本的go项目),可以换成dep的Gopkg.toml和Gopkg.lock或者glide的glide.yaml和glide.lock等.
-
vendor 目录(可选):vendor 是 Go 1.5 引入的机制,用于在项目本地缓存版本特定的依赖包,在引入 go modules 机制之前,可以实现基于 vendor 的可重现构建,以确保从相同构建的可执行文件源代码是等价的。go modules 本身可以在没有供应商的情况下实现可重现的构建。modules 本身可以在不需要 vendor 的情况下实现可重现的构建,但是 go modules 机制还保留了 vendor 目录(go mod vendor 在 vendor 下生成依赖项;go build -mod=vendor 启用基于 vendor 的构建),所以这里的 vendor 目录作为可选目录。一般我们只将vendor目录保留在项目的根目录下,否则会造成依赖选择上不必要的复杂性。
Go 1.11 引入了一个模块作为属于同一版本控制单元的包的集合。虽然 Go 支持项目/存储库中的多个模块,但这种管理方法可能会带来比一定比例的代码重复更多的复杂性。因此,如果项目结构中存在版本控制“分歧”,例如 app1 和 app2 版本并不总是同步,那么我建议将项目拆分为多个项目(存储库),每个项目都是一个单独的模块,用于单独的版本控制和演进.
库的Go语言项目目录结构
Go 1.4 发布时,Go 语言项目本身就去掉了 src 下的 pkg 层。这种结构变化对仅为库目的而构建的 Go 库类型项目的结构有一些影响。我们来看一个典型的 Go 库类型项目的结构,如下图所示。
我们看到库类型的项目结构也兼容 Go 项目的最低标准布局,但比旨在构建二进制可执行文件的 Go 项目更简单。
- 删除了cmd和pkg子目录:由于该库只是一个组件库,因此无需保留存放二进制文件主要包源文件的cmd目录;由于 Go 库项目的初衷是将 API 暴露给外界(开源或内部组织),因此没有必要将其聚合在 pkg 目录下。
- vendor不再可选:对于库类型的项目,我们不建议在项目中放置vendor目录来缓存库自身的第三方依赖;库项目应该只通过 go.mod(或其他包依赖管理工具的清单文件)明确说明项目依赖的模块或包以及版本要求。
关于internal
目录
对于上述任何类型的Go项目,对于不想暴露给外部引用,而只供内部使用的包,可以通过Go 1.4引入的内部包机制来实现项目结构。对于库项目,最简单的方法是在顶层添加一个内部目录,将所有不想暴露给外部的包都放在该目录下,例如项目中的 ilib1 和 ilib2下面的结构。
// 带internal的Go库项目结构
$tree -F ./chapter2/sources/GoLibProj
GoLibProj
├── LICENSE
├── Makefile
├── README.md
├── go.mod
├── internal/
│ ├── ilib1/
│ └── ilib2/
├── lib.go
├── lib1/
│ └── lib1.go
└── lib2/└── lib2.go
这样,根据go内部机制的原理,内部目录的ilib1和ilib2可以被其他目录(如lib.go、lib1/lib1.go等)的代码导入使用,GoLibProj目录为根目录,但不是通过 GoLibProj 目录之外的代码。这允许选择性地公开 API 包。当然 internal 可以放在项目结构中的任何目录级别,但是项目结构设计者清楚什么要暴露给外部代码以及什么只能在兄弟目录或子目录中使用是至关重要的。
对于旨在构建二进制可执行类型的项目,我们还可以将不想暴露给外部的包聚合到项目顶层路径的internal下,呼应暴露给包的聚合目录pkg外部。
总结
这篇文章详细介绍了Go语言项目结构布局的历史和Go项目结构的事实标准。本文中构建二进制可执行文件类型和库类型的两个项目参考结构经过多年的实践被Go社区认可并广泛使用,并且兼容Russ Cox提出的Go项目最小标准布局,具有参考价值对于稍大的 Go 项目。然而,它们不是必需的,在 Go 语言的早期,将所有源文件放在位于项目根目录的根包中的做法在一些小型项目中同样有效。
对于旨在构建二进制可执行类型的项目,受 Go 1.4 项目结构的影响,删除 pkg 层次结构也是许多项目选择的结构布局。
上述参考项目结构类似于产品设计和开发领域的“最小可行产品”(mvp)的思想,开发者可以根据自己的实际需要在这样一个最小“项目结构核心”的基础上进行扩展。
By 极客Furzoom
参考文章
go project layout
相关文章:
Go语言项目标准结构应该如何组织的?
这里写自定义目录标题Go项目本身的目录结构Go语言项目典型目录结构GO语言项目最小标准目录结构可执行的Go语言项目目录结构库的Go语言项目目录结构关于internal目录总结参考文章每当我们写一个非hello world实用程序的Go程序或库时,我们都会在项目结构、代码风格和标…...
设计模式简介
设计模式简介 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错…...
#详细介绍!!! 线程池的拒绝策略(经典面试题)
本篇单独讲解线程池的拒绝策略,介绍了当线程池任务满了之后,线程池会以什么样的方式来响应添加进来的任务 目录 一:理解线程池拒绝策略的触发情况代码理解 二:线程池的四种常见的拒绝策略 1.ThreadPoolExecutor.AbortPolicy 2…...
正则表达式作业
利用正则表达式完成下面的操作: 一、不定项选择题 能够完全匹配字符串"(010)-62661617"和字符串"01062661617"的正则表达式包括(A ) A. r"\(?\d{3}\)?-?\d{8}" B. r"[0-9()-]" C. r"[0-9(-)]*\d*&qu…...
《扬帆优配》交易拥挤度达历史极值 当前A股TMT板块性价比几何?
上周,A股商场企稳,但盘面风格分歧再度加深:很多资金涌入以ChatGPT、数字经济为代表的TMT板块,而新能源以及前期强势的“中字头”种类都呈现了回调。兴业证券计算显现,3月24日,TMT及电子板块的商场成交金额占…...
C/C++开发,无可避免的IO输入/输出(篇三).字符串流(内存流)IO处理
目录 一、字符串流 1.1 字符串流继承体系 1.2 字符串流本质-类模板std::basic_stringstream 1.3 字符串流缓冲-std::stringbuf 1.4 stringbuf与序列缓冲 1.5 字符串流的打开模式 二、字符串流的运用 2.1 格式转换是其拿手好戏 2.2 字符串流仅提供移动赋值 2.3 std::basic_str…...
什么是HTTP请求?【JavaWeb技术】
HTTP请求是指从客户端到服务器的请求消息,建立HTTP请求需要经历以下7个步骤才能请求成功。 (1)建立TCP连接 在HTTP开始工作前,Web浏览器需先通过网络和Web服务器连接,连接过程主要使用TCP/IP完成。 (2)Web浏览器向Web服务器发送请求命令 一旦…...
浅聊面试这件事
目录 哪个时间点适合跳槽 如何准备面试 面试原则 面试常见问题 哪个时间点适合跳槽 金三银四、金九银十,这些都📌标记为我们的最佳跳槽节点,但是这些节点真的是最佳的么,也需要因人而异。 如果公司年前不发年终奖,…...
【致敬未来的攻城狮计划】连续打卡第7天+瑞萨RA2E1点亮LED
开启攻城狮的成长之旅!这是我参与的由 CSDN博客专家 架构师李肯(http://yyds.recan-li.cn)和 瑞萨MCU (瑞萨电子 (Renesas Electronics Corporation) ) 联合发起的「 致敬未来的攻城狮计划 」的第 7 天,点击…...
Sam Altman专访:GPT-4没太让我惊讶,ChatGPT则让我喜出望外
导读ChatGPT、GPT-4 无疑是 2023 年年初人工智能界最大的「爆款」。3 月 26 日,OpenAI CEO、ChatGPT 之父 Sam Altman 接受了著名学者与科技播客、麻省理工大学研究员 Lex Fridman 的专访,Sam 分享了从OpenAI内部视角如何看待ChatGPT和GPT-4的里程碑式意…...
弯道超车的机会
弯道超车的机会 原文地址:https://bmft.tech/#/1-throught/0302-chance 前言 我一直很想把自己思考的东西表达出来,苦于语文成绩差,文字功力不够,想来想去也不知道用什么话来开场。我不喜欢站在高处对别人指指点点,…...
【设计模式】创建型模式之原型模式
【设计模式】创建型模式之原型模式 文章目录【设计模式】创建型模式之原型模式1.概述2. 构成3. 实现3.1 浅克隆3.2 深克隆1.概述 原型模式(Prototype Pattern):是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它…...
KMP算法——我欲修仙(功法篇)
个人主页:【😊个人主页】 系列专栏:【❤️我欲修仙】 学习名言:莫等闲、白了少年头,空悲切。——岳飞 系列文章目录 第一章 ❤️ 学习前的必知知识 第二章 ❤️ 二分查找 文章目录系列文章目录前言🚗&…...
【嵌入式Linux学习笔记】QT在Linux嵌入式设备上的使用
QT是目前主流的UI界面设计软件之一,Linux系统也支持QT应用,并且提供了很多方便的接口。所以有必要记录一下基于QT,在LCD屏幕上实现UI界面功能的各种细节。 学习视频地址:【正点原子】STM32MP157开发板 1. 系统配置 出于方便&am…...
js根据数据关键字实现模糊查询功能
js根据数据关键字实现模糊查询功能模糊查询实现模糊查询功能的步骤和一般方法第一步:创建假数据或请求接口数据第二步:分析数据格式,处理数据第三步:验证功能完整代码模糊查询 模糊查询功能是指在搜索或者查询时,允许…...
java获取对象属性
Field[] fields vo.getClass().getDeclaredFields(); for (Field field : fields) {//设置允许通过反射访问私有变量field.setAccessible(true);//获取字段的值String value "";Class<?> type field.getType();if (Date.class.equals(type)) {value DateU…...
51单片机(IIC协议OLED屏)
一、IIC协议 1、IIC协议概述 1.1、概述:IIC全称Inter-Integrated Circuit (集成电路总线) 是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双 工同步通信方式 1.2、特点:简单性和有效性。 由于接口直…...
你知道,华为对项目经理要求的3项技能5项素质是什么吗?
很多人一定在好奇,华为对项目经理的要求是什么呢?普通项目经理应具备什么素质,才能进入华为这样的大厂,在严峻的经济形势下无惧裁员呢? 一、三项软技能 我们在华为举办的项目经理论坛中找到了答案:对于华…...
优漫动游 提升效率常用的C4D技巧
C4D是近几年非常热的趋势,经常有人问3D相关的问题,想把自己在找捷径的过程中觉得最实用的小技巧分享给大家 1、快速定位层级和模型 模型的过程中,经常遇到模型层级多难定位的问题,逐级打开或者全部展开对于定位模型使…...
基于蚁群算法的时间窗口路径优化
目录 背影 蚁群算法的原理及步骤 基本定义 编程思路 适应度函数 算法的规则 特点 主要参数 代码 结果分析 展望 背影 现代物流配送对时间要求更高,是否及时配送是配送是否成功的重要指标,本文对路径优化加时间窗口,实现基于蚁群算法的时间窗口路径优化, 蚁群算法 基本…...
liunx
linux常用命令 mkdir :创建文件夹 rm -f :删除文件 docker cp 文件名 20f:容器内地址 将文件从linux系统移动到docker地址 ln -s 将两个文件做链接 compgen -u 查看所有用户 groups 查看所在组 vim 编辑 quit 退出 sudo su - root 获得root权限 cp dir1/…...
机动车发票组件【vue】
发票组件 问题反馈:在这就可以 Install-下载 npm install motorvehicles --savewarrning:我们推荐您设置key的,因为不存在它会带来数据的复用性问题usage-使用说明 import MotorVehiclesIvoice from motorvehiclesimport MotorVehiclesIvo…...
学习笔记-剖析k8s之StatefulSet的拓扑状态-3月day18
文章目录前言StatefulSetHeadless ServicePod的拓扑状态小结附前言 Deployment实际上并不足以覆盖所有的应用编排问题,原因在于Deployment对应用做了一个简单化的假设:一个应用的所有Pod,是完全一样的。所以,它们互相之间没有顺序…...
Java实现输出九九乘法口诀表,输入行数输出对应的梯形(平行四边形)这两个代码
目录 一、前言 二、代码部分 1.输出九九乘法口诀表的代码 三、程序运行结果(控制台输出) 一、前言 1.本代码是我在上学时写的,有一些地方没能完美实现,请包涵也请多赐教! 2.本弹窗界面可以根据简单的要求进行输…...
C++空间配置器
目录 1.什么是空间配置器 2.为什么需要空间配置器 3.SGI-STL空间配置器实现原理 3.1一级空间配置器 3.2二级空间配置器 3.2.1内存池 3.2.2 SGI-STL中二级空间配置器设计 3.3 空间配置器的默认选择 4.空间配置器与容器的结合 1.什么是空间配置器 空间配置器࿰…...
JConsole使用教程
JConsole是一个Java虚拟机的监控和管理工具,可以监控Java应用程序的内存使用、线程和类信息等。 以下是JConsole的使用教程: 1.启动JConsole JConsole是一个Java自带的工具,可以在bin目录下找到jconsole.exe文件。双击运行该文件即可启动JC…...
JS手写防抖和节流函数(超详细版整理)
1、什么是防抖和节流防抖(debounce):每次触发定时器后,取消上一个定时器,然后重新触发定时器。防抖一般用于用户未知行为的优化,比如搜索框输入弹窗提示,因为用户接下来要输入的内容都是未知的&…...
我的Macbook pro使用体验
刚拿到Mac那一刻,第一眼很惊艳,不经眼前一亮,心想:这是一件艺术品,太好看了吧 而后再体验全新的Macos 系统,身为多年的win用户说实话一时间还是难以接受 1.从未见过的访达,不习惯的右键 2. …...
炼石入选“首届工业和信息化领域商用密码应用峰会”典型方案
2023年3月22日-23日,浙江省经济和信息化厅、浙江省通信管理局、浙江省密码管理局、工业和信息化部商用密码应用产业促进联盟联合举办的“首届工业和信息化领域商用密码应用峰会”(以下简称峰会)在浙江杭州成功举办,旨在深入推进工…...
使用new bing chat成功了
步骤一:在扩展商店搜索并安装modheader 打开浏览器; 点击右上角的三个点图标,选择“更多工具” -> “扩展程序”; 在扩展程序页面上方的搜索框中输入“modheader”,然后点击“搜索商店”; 在搜索结果中找到“ModHeader”扩展程序,点击“添加至”按钮,然后再点击“添…...
济南网站建设jnwuyi/百度竞价推广是什么工作
本文将集中讨论如何使用CUDA代码创建一个非托管DLL,并在C#程序中使用它,列举的例子将展示在数组上做计算的for()循环的托管、非托管和新的.NET 4并行版本之间的一些差异。我将简要地介绍如何配置CUDA环境和运行示例程序,CUDA本身已经超出了本…...
高新网站建设哪家好/优质友情链接
场景:针对异常处理,我们原来的做法是一般在最外层捕获异常即可,例如在Controller中Controller public class HelloController {private static final Logger logger LoggerFactory.getLogger(HelloController.class);GetMapping(value &quo…...
做网站推广的公司发展前景/济南网站制作
2019独角兽企业重金招聘Python工程师标准>>> 1. 问题描述 通过CDH管理平台,进入Zookeeper管理界面,Zookeeper的平均请求延迟、最小请求延迟、最大请求延迟指标趋势图维持不变,指标数据异常。 2.问题复现 登录CDH平台,进…...
wordpress修改背景/推广页面
20172330 2017-2018-1 《Java程序设计》第三周学习总结 教材学习内容总结 这一章的主要内容是关于类与对象,通过对String类,Random类,Math类等一系列道德具体讲解与应用,让我们对创建对象有了更深的了解。 同时也对格式化输出进行…...
网站建设课程设计文献综述/网站建设推广公司
什么是生命周期? 生命周期就是一个对象从创建、运行、销毁的整个过程被称为生命周期 uniApp的生命周期是将微信小程序和它自身的结合了 1、应用的生命周期:(需要定义在App.vue里面) onLaunch:dang uni-app初始化完成触…...
医程通 网站做的太/天津百度快速排名优化
tcpdump是一个用于截取网络分组,并输出分组内容的工具。 tcpdump凭借强大的功能和灵活的截取策略,使其成为类UNIX系统下用于网络分析和问题排查的首选工具。tcpdump提供了源代码,公开了接口,因此具备很强的可扩展性,对…...