1.go源码解析之TCP连接(二)——Accept
2.[灵性编程]GO的金融金融依赖注入AND自动生成代码
3.golang源码系列---手把手带你看heap实现
4.图解Go里面的WaitGroup了解编程语言核心实现源码
5.go build介绍
6.go源码分析——类型
go源码解析之TCP连接(二)——Accept
go源码解析之TCP连接系列基于go源码1..5
连接是如何建立的
在上一章中,我们通过追踪net.Listen的源码源码调用,深入理解了socket的投资创建、端口绑定以及监听过程。金融金融最后,源码源码net.Listen返回了Listener(在具体情况下为TCPListener),投资26的源码补码本章将通过该Listener的金融金融Accept方法的跟踪,揭示连接建立的源码源码过程。
让我们逐步跟踪源码,投资探索连接建立的金融金融具体步骤:
1. TCPListener的Accept方法
此方法调用了TCPListener的内部方法accept。
随后,源码源码我们跳过ln.fd.accept和newTCPConn方法的投资调用,回顾上一章中关于KeepAlive配置项的金融金融讨论:KeepAlive是ListenConfig的一个属性,而ListenConfig与创建成功的源码源码监听netFD相关联。
如果KeepAlive值大于等于0,投资将设置socket开启KeepAlive功能。若为0,则默认设置TCP_KEEPINTVL和TCP_KEEPIDLE属性为秒,否则依据用户设定的时间。
2. 设置KeepAlive
setKeepAlive和setKeepAlivePeriod方法类似,领赞API源码负责设置socket属性。在这两个方法中,我们都执行了fd.pfd.SetsockoptInt操作,而pfd是netFD中的属性。
继续深入,观察poll.FD的SetsockoptInt方法,进而理解进行socket属性设置的过程。fd.Sysfd是创建系统socket的fd。net包中涉及监听、主动connect成功以及accept建立的socket,均通过netFD进行包装,因此,记住层级关系:netFD对poll.FD进行包装,poll.FD对系统fd进行包装。
额外知识:keepalive参数
setKeepAlive方法中的SO_KEEPALIVE用于开启keepalive总开关,而setKeepAlivePeriod中的TCP_KEEPINTVL与tcp_keepalive_intvl相关,TCP_KEEPIDLE与tcp_keepalive_time相关。TCP_KEEPCNT对应tcp_keepalive_probes,但代码中未找到使用实例。源码怎么加驱动
回到accept主流程,继续追踪ln.fd.accept方法调用。
3. netFD的accept方法
通过调用pfd.Accept(即poll.FD的Accept方法),我们深入到accept的内部实现。最终,连接成功时返回新连接socket的fd及主机地址信息。遇到EAGAIN错误(非阻塞模式下,系统调用立即返回)且fd.pd.pollable为true时,当前goroutine阻塞等待新消息(即新连接),之后再次调用accept接收连接。
简述pollDesc(即FD中的pd),它是IO多路复用在go语言中的集成,pd.waitRead等待io消息的到来。后续章节将详细探讨epoll在go语言网络库中的使用。
最后,netFD的accept方法调用newFD创建了netFD,此过程在上一章已有详细解释。
至此,连接建立的钓鱼软件源码分析整个调用链路基本完成,我们通过下图回顾整个过程。
4. newTCPConn
conn实现了接口类型Conn,其唯一属性是netFD,核心方法是对netFD方法的封装。
进一步,TCPConn继承自conn,它提供了ReadFrom方法,用于从Reader中读取数据并写入到TCPConn的socket上。
5. 小结
通过跟踪TCPListener的Accept方法,我们详细阐述了server侧接收新连接的过程。总结了关键点,并为下一章分析TCPConn的Read方法,深入理解数据读取过程奠定了基础。
[灵性编程]GO的依赖注入AND自动生成代码
依赖
总结下先有的获取对象依赖方式
比较原始的New,全局global保存
基于反射读取对象的依赖,程序启动时由DI库实例化(代表作dig等)
基于反射读取对象的依赖,编译前生成完整构建函数(代表作wire等)
第一种:最方便,直接快捷,大量依赖时候,但是因为是手动的,容易出现实例顺序非预期,不方便自动测试,mock等。
第二种:因为是启动时反射获取依赖的,需要定义额外的函数给DI系统解析,例如一个结构的注入必须要要额外的代码,非常麻烦,不建议使用
//提供者err:=c.Provide(func(conn*sql.DB)(*UserGateway,*CommentGateway,error){ //...})iferr!=nil{ //...}//使用者err:=c.Invoke(func(l*log.Logger){ //...})iferr!=nil{ //...}第三种,同样是基于反射,所以依然需要一个额外函数(只有配置信息)提供反射信息,生成同名函数,便捷度基本和手动New一致,wire由Google开源
funcInitializeNewGormProvider()*Gorm{ wire.Build(NewGormProvider,InitializeNewConfProvider)returnnil}我的方案原理和wire一样,根据配置信息生成自动构建函数,但是不基于反射,因为反射需要程序是完整的,编译后才读取信息,相对慢,需要每个目录改完手动执行wire.命令(每个目录每次花费1秒等)。
先看一个场景,数据库服务是依赖配置服务,从结构体就能看出来,不需要funcInitializeNewGormProvider()*Gorm{ }函数反射,未了更加准确(防止注入了不需要的内容)添加一个taginject:""和@Bean注解
//@BeantypeGormstruct{ conf*Conf`inject:""`}所以,注入其实是可以直接基于源码的信息都能实现的。
我只要实现一个go代码解析工具,就能生成和wire工具生成相同的代码,因为go源码的关键字和结构实在是太简单了,没有多少语法糖,做一下分词再按语法规则读取源码信息,工具实现比较容易。工具使用php实现(公司都是mac,php环境mac电脑自带,方便使用模版生成go代码)et/ctcp代码包:
在任意目录下执行go build cnet/ctcp命令。 正确执行go build依赖环境变量GOPATH中包含goc2p项目的泛域名跳转源码根目录。代码包导入路径相对于$GOROOT/src或GOPATH/src子目录,例如logging绝对路径为~/golang/goc2p/src/logging。多代码包编译
可以通过go build命令同时编译多个Go源码文件。但需注意,文件需在同一目录中。依赖代码包会自动编译,如app代码包依赖logging和basic,执行go build app时,会先检查并编译所需依赖。输出文件和命令标记
编译时,对于仅包含库源码文件的代码包,go build仅做检查性编译,不输出结果文件。使用标记-v可查看编译包名。结果文件名称与源码文件主文件名相同,使用标记-o可自定义输出文件名。标记-i安装未安装的依赖代码包。高级标记
其他常用标记如-p n限制并发数量、-n不实际运行、-buildmode=default指定编译模式等。标记用于控制编译行为,如链接器标记、编译器标记、链接器标记等。标记-race、-installsuffix控制输出目录。标记用于指定编译标签、自定义编译工具等。 通过go build命令,Go开发人员可以高效编译代码包及依赖,灵活控制编译行为,满足不同场景需求。go源码分析——类型
类型是Go语言中的核心概念,用于定义数据的结构和行为。类型可以分为基础类型和自定义类型,编译器会为每种类型生成对应的描述信息,这些信息构成了Go语言的类型系统。内置类型的数据结构在`runtime.type`文件中,而自定义类型的数据结构在`type.go`文件中,包括了类型名称、大小、对齐边界等属性。例如,切片的元素类型和map的键值类型都在其中有所体现。空接口`interface{ }`和非空接口`iface`是描述接口的底层结构体,分别用于表示不包含方法的接口和包含方法的接口。空接口的结构简单,包含类型和数据的位置信息,而非空接口的结构更复杂,包含接口的类型、实体类型和方法信息。接口的实现依赖于方法集的匹配,时间复杂度为O(m+n)。断言是判断一个类型是否实现了某个接口的机制,它依赖于接口的动态类型和类型元数据。类型转换和接口断言遵循类型兼容性原则,而反射提供了访问和操作类型元数据的能力,其核心是`reflect.Type`和`reflect.Value`两个结构体类型,分别用于获取类型信息和操作值。反射的关键在于明确接口的动态类型和类型实现了哪些方法,以及类型元数据与空接口和非空接口的数据结构之间的关系。
Go的执行原理以及Go的命令
Go的源码文件主要分为三类:命令源码文件、库源码文件和测试源码文件。
命令源码文件是Go程序的入口,被声明为main包,包含main函数。文件被安装后,会根据GOPATH设置存放于当前工作区的bin目录或GOBIN设置的目录。这些文件可以单独运行,使用go run命令直接执行,或通过go build或go install生成可执行文件。命令源码文件不应与其他文件混合在同一个代码包中。
库源码文件不具备命令源码文件的特征,是普通源码文件。文件被安装后,对应的归档文件(.a文件)会被存放在当前工作区的pkg目录下的平台相关目录。库源码文件不能通过go build或go install编译和安装。
测试源码文件以_test.go为后缀,并包含Test或Benchmark函数。Test函数接受*testing.T参数,用于功能测试;Benchmark函数接受*testing.B参数,用于性能测试。
命令方面,Go的最新版本1.提供了个基本命令,如build、get、install、run等。build命令用于编译代码包及其依赖;get命令用于下载远程代码仓库中的代码包;install命令用于编译并安装代码包;run命令用于运行命令源码文件。build和install命令会在指定目录生成可执行文件;run命令只能运行命令源码文件。install命令还负责将编译结果移动到bin目录或GOBIN目录。get命令会将代码包下载到GOPATH中的src目录。clean命令用于清除已编译生成的文件。
fmt命令用来格式化代码文件,通常与gofmt命令结合使用,格式化后的结果会覆盖源代码文件。test命令自动读取_test.go文件,生成并运行测试用的可执行文件。doc命令提供强大的文档功能,可以查看相应package的文档,甚至创建本地版本的golang.org文档。fix命令用于修复老版本代码到新版本,version命令查看当前Go版本,env命令查看Go环境变量,list命令列出当前安装的所有package。
综上所述,Go的源码文件分类清晰,命令提供了全面的编译、下载、安装、测试和文档支持,满足了开发者的需求。