<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Go on Cylon&#39;s Collection</title>
    <link>https://www.161616.top/tags/go/</link>
    <description>Recent content in Go on Cylon&#39;s Collection</description>
    <generator>Hugo -- 0.125.7</generator>
    <language>zh</language>
    <lastBuildDate>Sat, 21 Sep 2024 23:00:36 +0800</lastBuildDate>
    <atom:link href="https://www.161616.top/tags/go/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Goswagger - Skipping &#39;&#39;, recursion detected</title>
      <link>https://www.161616.top/goswagger-skipping-recursion-detected/</link>
      <pubDate>Sat, 21 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/goswagger-skipping-recursion-detected/</guid>
      <description>问题：当使用的结构体为嵌套格式，会提示 recursion detected 或 cannot find type definition
go 1 2 3 4 5 6 7 8 9 10 11 type Instance struct { metav1.TypeMeta Instances []InstanceItem `json:&amp;#34;instances&amp;#34; yaml:&amp;#34;instances&amp;#34; form:&amp;#34;instances&amp;#34; binding:&amp;#34;required&amp;#34;` ServiceSelector map[string]string `json:&amp;#34;serivce_selector&amp;#34; yaml:&amp;#34;serivce_selector&amp;#34; form:&amp;#34;serivce_selector&amp;#34;` } type InstanceItem struct { Name string `json:&amp;#34;name&amp;#34; yaml:&amp;#34;name&amp;#34; form:&amp;#34;name&amp;#34; binding:&amp;#34;required&amp;#34;` PromEndpoint string `json:&amp;#34;prom_endpoint&amp;#34; yaml:&amp;#34;prom_endpoint&amp;#34; form:&amp;#34;prom_endpoint&amp;#34; binding:&amp;#34;required&amp;#34;` Labels map[string]string `json:&amp;#34;labels&amp;#34; yaml:&amp;#34;labels&amp;#34; form:&amp;#34;labels&amp;#34;` } go swagger 注释为
text 1 2 3 4 5 6 7 8 9 10 // deleteInstance godoc // @Summary Remove prometheus instance.</description>
    </item>
    <item>
      <title>Gin - 参数默认值问题</title>
      <link>https://www.161616.top/gin-param-default-value/</link>
      <pubDate>Fri, 20 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/gin-param-default-value/</guid>
      <description>遇到问题：gin 使用 Bind 时无法填充，改成下面代码可以获取到
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 type User struct { Name string `form:&amp;#34;name,default=user1&amp;#34; json:&amp;#34;name,default=user2&amp;#34;` Age int `form:&amp;#34;age,default=10&amp;#34; json:&amp;#34;age,default=20&amp;#34;` } r := gin.Default() // way1 curl 127.0.0.1:8900/bind?name=aa // way2 curl -X POST 127.0.0.1:8900/bind -d &amp;#34;name=aa&amp;amp;age=30&amp;#34; // way3 curl -X POST 127.0.0.1:8900/bind -H &amp;#34;Content-Type: application/json&amp;#34; -d &amp;#34;{\&amp;#34;name\&amp;#34;: \&amp;#34;aa\&amp;#34;}&amp;#34; r.</description>
    </item>
    <item>
      <title>Gorm - BeforeDelete无法获取正确条目</title>
      <link>https://www.161616.top/gorm-before-delete/</link>
      <pubDate>Fri, 20 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/gorm-before-delete/</guid>
      <description>遇到问题：BeforeDelete 在删除时获取 SQL 不正确
BeforeDelete 代码如下
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func (t *Target) BeforeDelete(tx *gorm.DB) (err error) { // 找到与此 Target 相关的所有 Labels var labels []Label if err := tx.Model(t).Association(&amp;#34;Labels&amp;#34;).Find(&amp;amp;labels); err != nil { klog.V(4).Infof(&amp;#34;Error fetching labels: %v&amp;#34;, err) return err } for _, label := range labels { if err := tx.Delete(&amp;amp;label).Error; err != nil { klog.</description>
    </item>
    <item>
      <title>Go每日一库 - 使用 gin &#43; goswagger 构建 REST API 文档</title>
      <link>https://www.161616.top/golib-go-swagger/</link>
      <pubDate>Wed, 19 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/golib-go-swagger/</guid>
      <description>OpenAPI 什么是OpenAPI Swagger 是一套围绕 OpenAPI 规范构建的开源工具，可帮助我们设计，构建，记录和使用 REST API。
OpenAPI 规范（前名称为 Swagger 规范）是 REST API 的 API 描述格式。包括：
可用端点 ( 例如 /users) 以及每个 endpoint 上的操作 (例如 GET /users, POST /users) 操作参数，每个操作的输入和输出 认证方法 联系信息，许可证，使用条款等其他信息。 什么是 Swagger？ Swagger 是一组围绕 OpenAPI 规范构建的开源工具，有助于用户设计，构建，记录和使用 REST API，支持整个 API 生命周期的开发，从设计和文档到测试和部署。
使用 Swagger 的目的 标准化文档格式：Swagger (OpenAPI) 采用了准化 API 文档格式。通过使用 Swaggo（将注释转换为 Swagger2.0文档的包） 生成 Swagger 文档，Swagger 的结构化格式的文档，使开发人员更容易理解产品的 API 交互。 交互式文档体验：Swagger UI 与 Swaggo 集成，提供交互式且用户友好的界面，用于测试 API。Swaggo提供了一个自动生成的界面，允许开发人员浏览 Endpoint，查看请求/响应示例，甚至可以直接从文档执行 API 请求。这种交互式体验可提高开发人员的工作效率并加速 API 的采用。 自动且最新的文档：Swaggo 可自动从用户的 Go 代码生成 API 文档。这种自动化无需手动维护单独的文档文件。Swaggo 直接从用户的代码库中提取信息，包括 endpoint 详细信息，请求/响应模型和注释。使用这种方法可确保用户的 API 文档随着代码的更新而保持最新。 Swagger 与 Gin 的集成 拉取 Swaggo 使用如下命令下载swag</description>
    </item>
    <item>
      <title>Go设计模式</title>
      <link>https://www.161616.top/design-patterns/</link>
      <pubDate>Fri, 10 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/design-patterns/</guid>
      <description>创建型模式 工厂模式 概念说明 工厂模式 (factory pattern) 是在父类中提供一个创建对象的方法，是用于创建不同类型的对象，而无需指定对象的真实的类
工厂模式的特点：
对客户端隐藏对象创建的复杂逻辑 可以通过修改工厂类来创建对象而不影响客户端代码 提供创建对象的单一来源。 单个工厂类用以各组件保持一致性。 允许子类创建对象类型 图：工厂设计模式的示意图 Source：https://www.techcrashcourse.com/2015/10/factory-design-pattern.html
图片说明： Owl, Eagle, Sparrow 类都必须实现 Brid 接口， 该接口声明了一个名为 fly() 的方法。 每个类都将以不同的方式实现该方法。而使用工厂模式后的代码机构则为图所示，当 Owl, Eagle, Sparrow 实现了共同的接口，就可以将其对象传递给客户代码， 而无需提供额外数据。
而 “调用工厂方法的代码” 称为 “客户端代码”，这样可以做到 “不需要了解不同子类返回实际对象之间的差别”。客户端代码将所有 Brid Sanctuary 视为抽象的 Brid ，这样 ”客户端代码“ 知道所有鸟类对象都提供 fly() 方法， 但是并不关心其实现方式。
代码实现 brid.go
go 1 2 3 4 5 package main type Brid interface { Fly() } Owl.go
go 1 2 3 4 5 type Owl struct {} func (g *Owl) Fly() { fmt.</description>
    </item>
    <item>
      <title>Go中的类型断言与类型转换</title>
      <link>https://www.161616.top/go-type-assertion/</link>
      <pubDate>Tue, 24 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-type-assertion/</guid>
      <description>类型断言 类型断言 type assertion 并不是真正的将 interface 类型转换为另一种确定的类型，只是提供了对 interface 类型的值的访问，通常情况下，这是常见的需求
类型断言通过 语法 x.(T) ，这将会确定 x 变量中存储的值是否属于 T 类型，通常场景有两种：
如果 T 不是 interface 类型，而是一个具体的类型，那么这次断言将断言 x 的 动态类型是否与 T 相同 如果 T 是 interface 类型，这次断言 x 的动态类型是否实现了 T go 1 2 3 4 5 6 7 8 9 10 11 12 var x interface{} = &amp;#34;foo&amp;#34; var s string = x.(string) fmt.Println(s) // &amp;#34;foo&amp;#34; s, ok := x.(string) fmt.Println(s, ok) // &amp;#34;foo true&amp;#34; n, ok := x.</description>
    </item>
    <item>
      <title>如何使用go语言来检查端口可用性</title>
      <link>https://www.161616.top/goskill-port-is-available/</link>
      <pubDate>Fri, 06 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/goskill-port-is-available/</guid>
      <description>方法1：dial 使用 net.DialTimeout 去检查端口的技巧：
在通过Dial检查端口占用时，需要知道网络中常见的报错状态，而不是 err != nil 都为可用
Connection reset by peer connection reset by peer 这种错误情况下有以下几种场景：
基于包过滤的防火墙给予 RST；对于此情况，基于网络模型来说处于网络层与传输层之间的netfilter，如果是防火墙拒绝那么未到应用层无法确认端口 对端应用资源限制而reset，通常为负载过高；对于此场景是已到达应用层 客户端关闭了连接，而服务器还在给客户端发送数据；对于端口检查来说不会到这步 由上面可知，这种错误一定为占用
Connection timed out Connection timed out 这种场景根本就dial不成功，go中给出了一个专门的事件 opErr.Timeout() 来说明这个错误，故此错误将不能确认端口是否占用
Connection refused Connection refused 这种场景催在两种情况
对于 local 场景来说，这将表示端口未监听 对于远端场景来说，这种基本上表示 client 发往 remote ，remote不能接受 host:port 这个连接 通常对于存在两种情况，但多数为端口为监听
Misconfiguration, such as where a user has mistyped the port number, or is using stale information about what port the service they require is running on.</description>
    </item>
    <item>
      <title>Go每日一库 - gocolly</title>
      <link>https://www.161616.top/golib-gocolly/</link>
      <pubDate>Tue, 29 Mar 2022 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/golib-gocolly/</guid>
      <description>Introduction 本文对colly如何使用，整个代码架构设计，以及一些使用实例的收集。
Colly是Go语言开发的Crawler Framework，并不是一个完整的产品，Colly提供了类似于Python的同类产品（BeautifulSoup 或 Scrapy）相似的表现力和灵活性。
Colly这个名称源自 Collector 的简写，而Collector 也是 Colly的核心。
Colly Official Docs，内容不是很多，最新的消息也很就远了，仅仅是活跃在Github
Concepts Architecture 从理解上来说，Colly的设计分为两层，核心层和解析层，
Collector ：是Colly实现，该组件负责网络通信，并负责在Collector 作业运行时执行对应事件的回调。 Parser ：这个其实是抽象的，官网并未对此说明，goquery和一些htmlquery，通过这些就可以将访问的结果解析成类Jquery对象，使html拥有了，XPath选择器和CSS选择器 通常情况下Crawler的工作流生命周期大致为
构建客户端 发送请求 获取响应的数据 将相应的数据解析 对所需数据处理 持久化 而Colly则是将这些概念进行封装，通过将事件注册到每个步骤中，通过事件的方式对数据进行清理，抽象来说，Colly面向的是过程而不是对象。大概的工作架构如图
event 通过上述的概念，可以大概了解到 Colly 是一个基于事件的Crawler，通过开发者自行注册事件函数来触发整个流水线的工作
Colly 具有以下事件处理程序：
OnRequest：在请求之前调用 OnError ：在请求期间发生错误时调用 OnResponseHeaders ：在收到响应头后调用 OnResponse： 在收到响应后调用 OnHTML：如果接收到的内容是 HTML，则在 OnResponse 之后立即调用 OnXML ：如果接收到的内容是 HTML 或 XML，则在 OnHTML 之后立即调用 OnScraped：在 OnXML 回调之后调用 OnHTMLDetach：取消注册一个OnHTML事件函数，取消后，如未执行过得事件将不会再被执行 OnXMLDetach：取消注册一个OnXML事件函数，取消后，如未执行过得事件将不会再被执行 Reference
goquery
htmlquery
Utilities 简单使用 go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;github.</description>
    </item>
    <item>
      <title>Go每日一库 - deepcopier</title>
      <link>https://www.161616.top/golib-deepcopier/</link>
      <pubDate>Sat, 30 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/golib-deepcopier/</guid>
      <description>question: How use golang Copy one struct to another where structs have same members and different types
此时需要的库
github.com/ulule/deepcopier github.com/jinzhu/copier E.g.
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;github.</description>
    </item>
    <item>
      <title>goland设置import规范</title>
      <link>https://www.161616.top/go-mod-specification/</link>
      <pubDate>Thu, 14 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-mod-specification/</guid>
      <description>import 规范
引入了三种类型的包，标准库包，第三方包，程序内部包，建议采用如下方式进行组织你的包：
有顺序的引入包，不同的类型采用空格分离，
第一种标准库 第二是第三方包 第三是项目包。 在项目中不要使用相对路径引入包，在goland中可以使用如下设置自动格式化为引入标准
打开设置：Editor &amp;gt; Code Style &amp;gt; Go，选择import标签，将排序改为goimports, 剩下的按照自己喜好进行修改即可
Reference goimports-group</description>
    </item>
    <item>
      <title>goland在mod模式下不从vendor文件夹查找依赖</title>
      <link>https://www.161616.top/go-vendor-file-in-goland/</link>
      <pubDate>Sun, 13 Dec 2020 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-vendor-file-in-goland/</guid>
      <description>goland使用vendor作为获取依赖源 软件版本：
system：windows10 1709 terminal： wsl ubuntu1804 goland：201903 goland 打开项目时使用mod模式，无法识别外部包的依赖
根据goland官方提示，开启时，将忽略go.mod依赖描述，所以就找不到相对应的依赖，但是编译时正常的。可以看到下图中，external libraries 并没有加载外部的库导致了无法识别。
此时想要正常使用的话，可以按照提示操作
将 goland 改为gopath模式，执行go mod vendor 将依赖同步到vendor 。此时正常。
当依赖更新时，可以手动添加对应的依赖库，go mod tidy 后 。因为vendor中没有新的依赖，需要手动执行下go mod vendor即可正常使用。
使用vendor编译 在编译时，可以使用 -mod=vendor 标记，使用代码主目录文件夹下vendor目录满足依赖获取，go build -mod=vendor。此时，go build 忽略go.mod 中的依赖，（这里仅使用代码root目录下的vendor其他地方的将忽略）
GOFLAGS=-mod=vendor 设置顶级vendor作为依赖 go env -w GOFLAGS=&amp;quot;-mod=vendor&amp;quot; 进行设置。 取消 go env -w GOFLAGS=&amp;quot;-mod=&amp;quot;</description>
    </item>
    <item>
      <title>Go mod</title>
      <link>https://www.161616.top/go-mod/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-mod/</guid>
      <description>自从Go官方推出 1.11 之后，增加新的依赖管理模块并且更加易于管理项目中所需要的模块。模块是存储在文件树中的 Go 包的集合，其根目录中包含 go.mod 文件。 go.mod 文件定义了模块的模块路径，它也是用于根目录的导入路径，以及它的依赖性要求。每个依赖性要求都被写为模块路径和特定语义版本。
从 Go 1.11 开始，Go 允许在 $GOPATH/src 外的任何目录下使用 go.mod 创建项目。在 $GOPATH/src 中，为了兼容性，Go 命令仍然在旧的 GOPATH 模式下运行。从 ==Go 1.13== 开始，模块模式将成为默认模式。
使用模块开发 Go 代码时出现的一系列常见操作：
创建一个新模块。 添加依赖项。 升级依赖项。 删除未使用的依赖项。 要使用go module,首先要设置 ==GO111MODULE=on== ,如果没设置，执行命令的时候会有提示。
==GO111MODULE== 的取值为 off, on, or auto (默认值，因此前面例子里需要注意2个重点)。
off: GOPATH mode，查找vendor和GOPATH目录 on：module-aware mode，使用 go module，忽略GOPATH目录 auto：如果当前目录不在$GOPATH 并且 当前目录（或者父目录）下有go.mod文件，则使用GO111MODULE， 否则仍旧使用 GOPATH mode。 sh 1 2 export GO111MODULE=on export GOPROXY=https://goproxy.io ## 设置代理 go mod 参数说明 commond 说明 download download modules to local cache (下载依赖的module到本地cache)) edit edit go.</description>
    </item>
    <item>
      <title>go net/http使用</title>
      <link>https://www.161616.top/go-net/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-net/</guid>
      <description>Go语言标准库内建提供了net/http包，涵盖了HTTP客户端和服务端的具体实现。使用net/http包，我们可以很方便地编写HTTP客户端或服务端的程序。
http服务端的创建流程 在使用http/net包创建服务端只需要两个步骤 绑定处理器函数 func(ResponseWriter, *Request)与 启用监听 http.ListenAndServe。
go 1 2 3 4 5 6 7 8 9 10 package main import &amp;#34;net/http&amp;#34; func main() { http.HandleFunc(&amp;#34;/&amp;#34;, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(&amp;#34;123&amp;#34;)) }) http.ListenAndServe(&amp;#34;:8080&amp;#34;, nil) } 通过分析net/http包中server.go 在执行创建http服务端主要执行了下面几个步骤：
http.HandleFunc 绑定处理函数 所有的操作的方法都属于一个结构体 ServeMux m: 用户传入的路由和处理方法的映射表，路由和处理函数被定义为结构体muxEntry的属性 mu： 实例化出来的对象的读写锁 调用DefaultServeMux.Handle() 在DefaultServeMux.Handle()中调用DefaultServeMux.HandleFunc(pattern, handler) 在将传入http.HandleFunc()的回调函数，与路由的映射信息，放到该DefaultServeMux的属性中 映射map中 muxEntry http.ListenAndServe 启动服务监听 实例化一个server结构体 调用 ListenAndServe() ListenAndServe()中 net.Listen(&amp;quot;tcp&amp;quot;, addr) 启动tcp服务监听 Serve()中 appcet()处理用户连接，go c.serve(connCtx) 处理业务段（如判断信息，拼接http、找到对应处理函数） 综上所述，net/http server.go 一切的基础为ServeMux 和 Handler</description>
    </item>
    <item>
      <title>Go socket TCP协议实现</title>
      <link>https://www.161616.top/go-tcp-in-go/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-tcp-in-go/</guid>
      <description>在TCP/IP协议中，“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识，那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。
常用的Socket类型有两种：流式Socket（SOCK_STREAM）和数据报式Socket（SOCK_DGRAM）。流式是一种面向连接的Socket，针对于面向连接的TCP服务应用；数据报式Socket是一种无连接的Socket，对应于无连接的UDP服务应用。
套接字通讯原理示意
TCP的C/S架构 在整个通信过程中，服务器端有两个socket参与进来，但用于通信的只有conn这个socket。它是由 listener创建的。隶属于服务器端。客户端有一个socket参与进来。
net.Listen() 建立一个用于连接监听的套接字 listen.Accept() // 阻塞监听客户端连接请求，成功用于连接，返回用于通信的socket net.Dial() 客户端向服务端发起连接建立一个socket连接
并发的C/S模型通信 Server Accept()函数的作用是等待客户端的链接，如果客户端没有链接，该方法会阻塞。如果有客户端链接，那么该方法返回一个Socket负责与客户端进行通信。所以，每来一个客户端，该方法就应该返回一个Socket与其通信，因此，可以使用一个死循环，将Accept()调用过程包裹起来。
需要注意，实现并发处理多个客户端数据的服务器，就需要针对每一个客户端连接，单独产生一个Socket，并创建一个单独的goroutine与之完成通信。
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;net&amp;#34; &amp;#34;strings&amp;#34; ) func handleConnect(conn net.</description>
    </item>
    <item>
      <title>Go 函数 function</title>
      <link>https://www.161616.top/go-function/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-function/</guid>
      <description>golang保留的函数 init(), main()是golang的保留函数，有如下特点：
main() 只能用在main包中，仅可定义一个，init() 可定义任意包，可重复定义，建议只定义一个 两个函数定义时不能有任何返回值 只能由go自动调用，不可被引用 init() 先于 main() 执行，并不能被其他函数调用，执行时按照main import顺序执行。 包的执行顺序 Go的初始化和执行总是从main.main函数（main包导入其它的包） 同包下的不同 .go 文件，按照以文件名或包路径名的字符串顺序“从小到大”排序顺序执行 其他的包只有被main包 import 才会执行，按照 import 的先后顺序执行; 如果某个包被多次导入的话，在执行的时候只会导入一次; 当一个包被导入时，如果它还导入了其它的包，则先将其它的包包含进来; 导入顺序与初始化顺序相反 main =&amp;gt; p1 =&amp;gt; p2 | p2 =&amp;gt; p1 =&amp;gt; p main被最后一个初始化，因其总是依赖其他包 函数 函数是将具有独立功能的代码组织成为一个整体，使其具有特殊功能的代码集。在Go语言中，函数是一种数据类型，其特性有如下：
支持匿名函数 支持带有变量名的返回值 支持多值返回 支持匿名函数 不支持重载，一个包中不能有两个名字一样的函数。 定义语法
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 func test(){ } func test(a int, b int){ } func test(a,b int){ } func test(a,b int list.</description>
    </item>
    <item>
      <title>Go 数据结构</title>
      <link>https://www.161616.top/go-datastruct/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-datastruct/</guid>
      <description>Go语言将数据类型分为四类：基础类型、复合类型、引用类型和接口类型。
基础数据类型包括：
基础类型： - 布尔型、整型、浮点型、复数型、字符型、字符串型、错误类型。 复合数据类型包括： - 指针、数组、切片、字典、通道、结构体、接口。 基础数据类型 布尔值和布尔表达式 布尔类型的变量取值结果要么是真，要么是假，用bool关键字进行定义
布尔类型默认值为 false
指定格式的输出 %t
语法 描述/结果 !b 逻辑非操作符 b值为true 则 操作结果为false a || b 短路逻辑或，只要布尔值 a b 中任何一个为true表达式结果都为true a &amp;amp;&amp;amp; b 短路逻辑与，两个表达式a b都为true，则整个表达式结果为true x &amp;gt; y 表达式x的值小于表达式Y的值，则表达式的结果为true 数值类型 go语言提供了大内置的数值类型，标准库也提供了big.Int类型的整数，和big.Rat类型的有理数，这些都是大小不限（只限于机器内存）
整型 GO语言提供了11种整型，包含5种有符号，和5种无符号的与一种用于存储指针的整数类型。Go语言允许使用byte来作为无符号uint8类型的同义词，在使用单个字符时提倡使用rune来替代 int32
类型 存储空间 取值范围 byte 8-bit 同uint8 int 系统决定 依赖不通平台实现，32位操作系统为int32的值范围，64位操作系统为int64的值范围 int8 8-bit [-128, 127] ，表示 UTF-8 字符串的单个字节的值，对应 ASCII 码的字符值 int16 16-bit [-32678, 32767] int32 32-bit [2147483648, 2147483647] int64 64-bit [-9223372036854775808 , 9223372036854775807] rune 32-bit 同uint32，表示 单个 Unicode 字符 uint 系统决定 依赖不通平台下的实现，可以是uint32或uint64 uint8 8-bit uint16 16-bit [0, 65535] uint32 32-bit [0, 4294967295] uint64 64-bit [0, 18446744073709551615] uintptr 系统决定 一个可以恰好容纳指针值得无符号整数类型（32位操作系统为uint32的值范围，64位系统为uint64的值范围） 浮点类型 Go语言提供了两种类型的浮点类型和两种类型的复数类型，</description>
    </item>
    <item>
      <title>Go 运算符</title>
      <link>https://www.161616.top/go-arithmetic/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-arithmetic/</guid>
      <description>算术运算符 运算符 示例 结果 + 10 + 5 15 - 10 - 5 5 * （除数不能为0） 10 * 5 50 / 10 / 5 2 % （除数不能为0） 10 % 3 1 ++ a = 0; a++ a = 1 &amp;ndash; a = 2; a&amp;ndash; a = 1 总结
除法/取余运算除数不能为0 只有后自增/减，没有前自增/减。没有 ++a 或 --a 只有 a++ 或 a-- 输入半径，计算圆的面积和周长并打印出来（PI为3.14）
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package main import &amp;#34;fmt&amp;#34; func main() { const PI = 3.</description>
    </item>
    <item>
      <title>Go每日一库 - 时间格式化</title>
      <link>https://www.161616.top/golib-timeformat/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/golib-timeformat/</guid>
      <description>该文可以快速在Go语言中获得时间的计算。
在Go中获取时间 如何获取当前时间 go 1 2 3 4 now := time.Now() fmt.Printf(&amp;#34;current time is :%s&amp;#34;, now) current time is :2009-11-10 23:00:00 +0000 UTC m=+0.000000001 如何获取UNIX Timestamp go 1 2 cur_time := time.Now().Unix() fmt.Printf(&amp;#34;current unix timestamp is :%v\n&amp;#34;, cur_time ) 如何获取当日0:00:00 0:00:00 go 1 2 3 4 5 now := time.Now() date := time.Date(now.Year(), now.Month(), now.Day(),0, 0, 0, 0, time.Local) fmt.Printf(&amp;#34;date is :%s&amp;#34;, date) date is :2021-04-13 00:00:00 +0800 如何获取时区时间 标准时间 time.</description>
    </item>
    <item>
      <title>Go每日一库 - 使用go操作dbus</title>
      <link>https://www.161616.top/golib-gobus/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/golib-gobus/</guid>
      <description>github https://github.com/godbus/dbus
增加一个端口
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package main import ( &amp;#34;github.com/godbus/dbus/v5&amp;#34; ) func main() { cli, err := dbus.SystemBus() if err != nil { panic(err) } obj := cli.Object(&amp;#34;org.fedoraproject.FirewallD1&amp;#34;, &amp;#34;/org/fedoraproject/FirewallD1&amp;#34;) call := obj.Call(&amp;#34;oorg.fedoraproject.FirewallD1.zone.addPort&amp;#34;, 0, &amp;#34;public&amp;#34;, &amp;#34;81&amp;#34;, &amp;#34;tcp&amp;#34;, &amp;#34;30000&amp;#34;) if call.Err != nil { panic(call.Err) } } go-dbus 简单教程 https://blog.csdn.net/mathmonkey/article/details/38095289</description>
    </item>
    <item>
      <title>Go面向对象</title>
      <link>https://www.161616.top/go-object/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-object/</guid>
      <description>所谓的面向对象其实就是找一个专门做这个事的人来做，不用关心具体怎么实现的。所以说，面向过程强调的是过程，步骤。而面向对象强调的是对象，也就是干事的人。
Go语言：面向对象语言特性 方法
嵌入
接口
没有类
支持类型。 特别是， 它支持structs。 Structs是用户定义的类型。 Struct类型(含方法)提供类似于其它语言中类的服务。
Structs 一个struct定义一个状态。 这里有一个strudent struct。 它有一个Name属性和一个布尔类型的标志Real，告诉我们它是一个真实的strudent还是一个虚构的strudent。 Structs只保存状态，不保存行为。
go 1 2 3 4 type Creature struct { Name string Real bool } 为结构体添加方法 方法是对特定类型进行操作的函数。 它们有一个接收器条款，命令它们对什么样的类型可进行操作。 这里是一个Hello()方法，它可对student结构进行操作，并打印出它们的状态：
go 1 2 3 func (s Student) Hello() { fmt.Printf(&amp;#34;Name: &amp;#39;%s&amp;#39;, Real: %t\n&amp;#34;, s.Name, s.Real) } func (s Student) func_name(){} 这是一个不太常见的语法，但是它非常的具体和清晰，不像this的隐喻性。
一般在定义方法时，需要定义为结构体的指针，值类型的在修改结构体属性时，无法修改其内容
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package main import &amp;#34;fmt&amp;#34; type human struct { Name string Real bool } type Student struct { human Id int } func (h human) Hello() { fmt.</description>
    </item>
    <item>
      <title>Go协程安全</title>
      <link>https://www.161616.top/go-goroutine-security/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-goroutine-security/</guid>
      <description>多路复用 Go语言中提供了一个关键字select，通过select可以监听channel上的数据流动。select的用法与switch语法类似，由select开始一个新的选择块，每个选择条件由case语句来描述。只不过，select的case有比较多的限制，其中最大的一条限制就是每个case语句里必须是一个IO操作。
select 语法如下：
go 1 2 3 4 5 6 7 8 select { case &amp;lt;-chan1: // 如果chan1成功读到数据，则进行该case处理语句 case chan2 &amp;lt;- 1: // 如果成功向chan2写入数据，则进行该case处理语句 default: // 如果上面都没有成功，则进入default处理流程 } 在一个select语句中，会按顺序从头至尾评估每一个发送和接收的语句；如果其中的任意一语句可以继续执行(即没有被阻塞)，那么就从那些可以执行的语句中任意选择一条来使用。如果没有任意一条语句可以执行(即所有的通道都被阻塞)，那么有两种可能的情况：⑴ 如果给出了default语句，那么就会执行default语句，同时程序的执行会从select语句后的语句中恢复。⑵ 如果没有default语句，那么select语句将被阻塞，直到至少有一个channel可以进行下去。
在一般的业务场景下，select不会用default，当监听的流中再没有数据，IO操作就 会阻塞现象，如果使用了default，此时可以出让CPU时间片。如果使用了default 就形成了非阻塞状态，形成了忙轮训，会占用CPU、系统资源。
阻塞与非阻塞使用场景
阻塞： 如：在监听超时退出时，如果100秒内无操作，择退出，此时添加了default会形成忙轮训，超时监听变成了无效。 非阻塞： 如，在一个只有一个业务逻辑处理时，主进程控制进程的退出。此时可以使用default。 定时器 Go语言中定时器的使用有三个方法
time.Sleep() time.NewTimer() 返回一个时间的管道， time.C 读取管道的内容 time.After(5 * time.Second) 封装了time.NewTimer()，反回了一个 time.C的管道 示例
go 1 2 3 select { case &amp;lt;-time.After(time.Second * 10): } 锁和条件变量 Go语言中为了解决协程间同步问题，提供了标准库代码，包sync和sync/atomic中。
互斥锁 互斥锁是传统并发编程对共享资源进行访问控制的主要手段，它由标准库sync中的Mutex结构体类型表示。sync.Mutex类型只有两个公开的指针方法，Lock和Unlock。Lock锁定当前的共享资源，Unlock进行解锁。
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;runtime&amp;#34; &amp;#34;sync&amp;#34; &amp;#34;time&amp;#34; ) var mutex sync.</description>
    </item>
    <item>
      <title>Go协程通讯</title>
      <link>https://www.161616.top/go-goroutine-communication/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-goroutine-communication/</guid>
      <description>channel是Go语言中的一个核心数据类型，channel是一个数据类型，主要用来解决协程的同步问题以及协程之间数据共享（数据传递）的问题。在并发核心单元通过它就可以发送或者接收数据进行通讯，这在一定程度上又进一步降低了编程的难度。
goroutine运行在相同的内存地址空间，channel可以避开所有内存共享导致的坑；通道的通信方式保证了同步性。数据通过channel：同一时间只有一个协程可以访问数据：所以不会出现数据竞争，确保并发安全。
channel的定义 channel是对应make创建的底层数据结构的引用。 创建语法： make(chan Type, capacity)
go 1 2 3 4 5 6 7 channel := make(chan bool) //创建一个无缓冲的bool型Channel ，等价于make(chan Type, 0) channel := make(chan bool, 1024) //创建一个有缓冲，切缓冲区为1024的bool型Channel channel &amp;lt;- x //向一个Channel发送一个值 &amp;lt;- channel //从一个Channel中接收一个值 x = &amp;lt;- channel //从Channel c接收一个值并将其存储到x中 x, ok = &amp;lt;- channel //从Channel接收一个值，如果channel关闭了或没有数据，那么ok将被置为false channel是一个引用类型，当复制一个channel或用于函数参数传递时，我们只是拷贝了一个channel引用，因此调用者和被调用者将引用同一个channel对象。和其它的引用类型一样，channel的零值（定义未初始化）也是nil。
在默认情况下，channel接收和发送数据都是阻塞的，（channel &amp;lt;- 1，写端写数据，读端不在读。写端阻塞； str := &amp;lt;-channel 读端读数据， 同时写端不在写，读端阻塞。）除非另一端已经准备好，这样就使得goroutine同步变的更加的简单，而不需要显式的lock。
示例
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;runtime&amp;#34; &amp;#34;time&amp;#34; ) var c = make(chan int32) func printstr(s string) { for _, value := range s { fmt.</description>
    </item>
    <item>
      <title>go语言的并发编程gorouting</title>
      <link>https://www.161616.top/go-goroutine/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-goroutine/</guid>
      <description>并行和并发 并发编程是指在一台处理器上“同时”处理多个任务。
宏观并发：在一段时间内，有多个程序在同时运行。
微观并发：在同一时刻只能有一条指令执行，但多个程序指令被快速的轮换执行，使得在宏观上具有多个进程同时执行的效果，但在微观上并不是同时执行的，只是把时间分成若干段，使多个程序快速交替的执行。
并行 parallel：同一时刻，多条指令在多个处理器上同时执行。
并发 concurrency：在同一时刻只能有一条指令执行，但多个进程指令被快速的轮换执行，使得在宏观上具有多个进程同时执行的效果，但在微观上并不是同时执行的，只是把时间分成若干段，通过cpu时间片轮转使多个进程快速交替的执行。
通俗来讲，并行是两组队列同时使用一个进程；并发是两个队列分别交替使用两个进程
进程并发 程序，以Go语言为例，是指编译好的二进制文件，在磁盘上，不占用系统资源(cpu、内存、打开的文件、设备、锁&amp;hellip;.)
进程，是一个抽象的概念，与操作系统原理联系紧密。以Go语言为例，将编译好的程序运行起来，在内存空间中形成一个独立的内存体，内存体有自己的独立空间，上级挂靠单位是操作系统。
进程是操作系统进行资源分配和调度的一个独立单位，一般由程序，数据集合和进程控制块三部分组成。
程序：描述进程完成的功能，是控制进程执行的指令集； 数据集合：程序在执行时所需要的数据和工作区； 程序控制块PCB：Program Control Block，包含进程的描述信息和控制信息，是进程存在的唯一标志。 进程是活跃的程序，占用系统资源。在内存中执行。同一个程序也可以加载为不同的进程(彼此之间互不影响)
进程状态 进程基本的状态有5种。分别为初始态，就绪态，运行态，挂起态与终止态。其中初始态为进程准备阶段，常与就绪态结合来看。
线程的任务调度 大部分操作系统的任务调度是采用时间片轮转的抢占式调度方式。
时间片轮转是指，在一个进程中，当线程任务执行几毫秒后，由操作系统内核进行调度，通过硬件计数器终端处理器，让线程强行暂停，并将该线程的寄存器放入内存中，通过查看线程列表决定接下来执行哪一个线程，并从内存中恢复该线程的寄存器，最后恢复该线程的执行，从而去执行下一个任务。
在时间片轮转中，任务执行那段时间叫做时间片，任务正在执行时的状态叫运行状态，被暂停的线程任务状态叫做就绪状态，意为等待下一个属于它的时间片的到来。
由于CPU的执行效率非常高，（i5 6600 约200亿/秒，奔腾4 约13亿/秒）CPU preformance 时间片非常短，在各个任务之间快速地切换，给人的感觉就是多个任务在“同时进行”，这也就是我们所说的并发。多任务运行过程的示意图如下：
进程实现并发时会出现的问题呢 孤儿进程: 父进程先于子进程结束，则子进程成为孤儿进程，子进程的父进程成为init进程，称为init进程领养孤儿进程。
僵尸进程: 进程终止，父进程尚未回收，子进程残留资源（PCB）存放于内核中，变成僵尸（Zombie）进程。
线程并发 在早期操作系统当中，没有线程的概念，进程是最小分配资源与执行单位，可以看做是一个进程中只有一个线程，故进程即线程。所以线程LWP被称为：：Lightweight process，轻量级的进程，是程序执行中一个单一的顺序控制流程，在Linux操作系统下，线程的本质仍是进程。
线程有独立的PCB，但没有独立的地址空间，各个线程之间共享程序的内存空间。
进程和线程的区别 进程：最小分配资源单位，可看成是只有一个线程的进程。 线程：最小的执行单位 一个进程由一个或多个线程组成 进程之间相互独立，同一进程下的各个线程之间共享程序的内存空间 协程并发 协程 coroutines，是一种基于线程之上，但又比线程更加轻量级的存在，这种由程序来管理的轻量级线程叫做『用户空间线程』，具有对内核来说不可见的特性。
多数语言在语法层面并不直接支持协程，而是通过库的方式支持，但用库的方式支持的功能也并不完整，比如仅仅提供协程的创建、销毁与切换等能力。如果在这样的轻量级线程中调用一个同步 IO 操作，比如网络通信、本地文件读写，都会阻塞其他的并发执行轻量级线程，从而无法真正达到轻量级线程本身期望达到的目标。
协程和线程的区别 占用资源：线程，初始单位为1MB,固定不可变；协程初始一般为 2KB，可随需要而增大。 调度：线程，由操作系统内核完成，协程，由用户完成。 性能： 线程，占用资源高，频繁创建销毁带来性能问题。占用资源小，不会带来严重的性能问题。 数据： 线程，多线程需要锁机制确保数据一致性和可见性；而线程因为只有一个进程，不存在同时读/写冲突，协程中控制共享数据不用加锁，顾执行效率较线程高。 Go并发 goroutine Go语言在语言级别支持协程，叫goroutine。Go语言标准库提供的所有系统调用操作（包括所有同步IO操作），都会出让CPU给其他goroutine。这种轻量级线程的切换管理不依赖于系统的线程和进程，也不需要依赖于CPU的核心数量。
Go语言为并发编程而内置的上层API基于顺序通信进程模型CSP(communicating sequential processes)。这就意味着显式锁都是可以避免的，因为Go通过相对安全的通道发送和接受数据以实现同步，这大大地简化了并发程序的编写。
Go语言中的并发程序主要使用两种手段来实现。goroutine和channel。
什么是goroutine Go语言作者Rob Pike说， “Goroutine是一个与其他goroutines并发运行在同一地址空间的Go函数或方法。一个运行的程序由一个或更多个goroutine组成。它与线程、协程、进程等不同。它是一个goroutine*。</description>
    </item>
    <item>
      <title>Go语言数据类型转换</title>
      <link>https://www.161616.top/goskill-golang-type-convert/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/goskill-golang-type-convert/</guid>
      <description>string in mutual conversion go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // int to int64 m := int64(n) // int64 to int n := int(m) // string to int int,err := strconv.Atoi(string) // string to int64 int64, err := strconv.ParseInt(string, 10, 64) // int to string string := strconv.</description>
    </item>
    <item>
      <title>Go中的signal处理</title>
      <link>https://www.161616.top/go-signal/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-signal/</guid>
      <description>什么是信号 在计算机科学中，信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制，用来提醒进程一个事件已经发生。
当一个信号发送给一个进程，操作系统中断了进程正常的控制流程，如果进程定义了对信号的处理，此时，程序将进入捕获到的信号对应的处理函数，否则执行默认的处理函数。
Linux中信号的介绍 在Linux系统共定义了64种信号，分为两大类：实时信号与非实时信号，1-31为非实时，32-64种为实时信号。
非实时信号： 也称为不可靠信号，为早期Linux所支持的信号，不支持排队，信号可能会丢失, 比如发送多次相同的信号, 进程只能收到一次. 信号值取值区间为1~31； 实时信号： 也称为可靠信号，支持排队, 信号不会丢失, 发多少次, 就可以收到多少次. 信号值取值区间为32~64 Linux操作系统中，在终端上执行 kill -l 便可看到系统定义的所有信号
信号表 POSIX.1-1990标准信号 此表参考自：POSIX信号
信号 值 动作 说明 SIGHUP 1 Term 终端控制进程结束(终端连接断开) SIGINT 2 Term 用户发送INTR字符(Ctrl+C)触发 SIGQUIT 3 Core 用户发送QUIT字符(Ctrl+/)触发 SIGILL 4 Core 非法指令(程序错误、试图执行数据段、栈溢出等) SIGABRT 6 Core 调用abort函数触发 SIGFPE 8 Core 算术运行错误(浮点运算错误、除数为零等) SIGKILL 9 Term 无条件结束程序(不能被捕获、阻塞或忽略) SIGSEGV 11 Core 无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作) SIGPIPE 13 Term 消息管道损坏(FIFO/Socket通信时，管道未打开而进行写操作) SIGALRM 14 Term 时钟定时信号 SIGTERM 15 Term 结束程序(可以被捕获、阻塞或忽略) SIGUSR1 30,10,16 Term 用户保留 SIGUSR2 31,12,17 Term 用户保留 SIGCHLD 20,17,18 Ign 子进程结束(由父进程接收) SIGCONT 19,18,25 Cont 继续执行已经停止的进程(不能被阻塞) SIGSTOP 17,19,23 Stop 停止进程(不能被捕获、阻塞或忽略) SIGTSTP 18,20,24 Stop 停止进程(可以被捕获、阻塞或忽略) SIGTTIN 21,21,26 Stop 后台程序从终端中读取数据时触发 SIGTTOU 22,22,27 Stop 后台程序向终端中写数据时触发 更多的信号说明请查阅man7</description>
    </item>
    <item>
      <title>如何使用golang通过进程ID找到进程名称</title>
      <link>https://www.161616.top/goskill-process-id/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/goskill-process-id/</guid>
      <description>一个很好的问题：How golang to get process name by process id (pid)?
目前看来go api并没有提供通过pid获取进程名称的方法，可以通过 /proc/&amp;lt;pid&amp;gt;/cmdline来获取对应的进程名称，也可以通过 readlink /proc/6530/exe 来获取
/proc/&amp;lt;pid&amp;gt;/cmdline 获取的为运行进程的名称，通常包含一些特殊字符。例如 &amp;quot;-bash\x00&amp;quot;，sshd: root@pts/0 readlink /proc/6530/exe 获取的为对应进程运行的程序的路径 go 1 2 pid := os.Getppid() contents, err := ioutil.ReadFile(fmt.Sprintf(&amp;#34;/proc/%d/cmdline&amp;#34;,pid)) go 1 2 pid := os.Getppid() contents, err := os.Readlink(fmt.Sprintf(&amp;#34;/proc/%d/cmdline&amp;#34;,pid)) Reference process name from pid</description>
    </item>
    <item>
      <title>使用go语言颁发CA证书</title>
      <link>https://www.161616.top/goskill-x509-in-go/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/goskill-x509-in-go/</guid>
      <description>本篇文章中，将描述如何使用go创建CA，并使用CA签署证书。在使用openssl创建证书时，遵循的步骤是 创建秘钥 &amp;gt; 创建CA &amp;gt; 生成要颁发证书的秘钥 &amp;gt; 使用CA签发证书。这种步骤，那么我们现在就来尝试下。
创建证书的颁发机构 首先，会从将从创建 CA 开始。CA 会被用来签署其他证书
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 对证书进行签名 ca := &amp;amp;x509.Certificate{ SerialNumber: big.NewInt(2019), Subject: pkix.Name{ CommonName: &amp;#34;domain name&amp;#34;, Organization: []string{&amp;#34;Company, INC.&amp;#34;}, Country: []string{&amp;#34;US&amp;#34;}, Province: []string{&amp;#34;&amp;#34;}, Locality: []string{&amp;#34;San Francisco&amp;#34;}, StreetAddress: []string{&amp;#34;Golden Gate Bridge&amp;#34;}, PostalCode: []string{&amp;#34;94016&amp;#34;}, }, NotBefore: time.Now(), // 生效时间 NotAfter: time.Now().AddDate(10, 0, 0), // 过期时间 年月日 IsCA: true, // 表示用于CA // openssl 中的 extendedKeyUsage = clientAuth, serverAuth 字段 ExtKeyUsage: []x509.</description>
    </item>
    <item>
      <title>通过Go语言中阐述TCP Handshake</title>
      <link>https://www.161616.top/go-tcp-hadshake/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-tcp-hadshake/</guid>
      <description>TCP的三次握手 所谓三次握手 Three-Way Handshake 是指建立一个TCP连接时，需要客户端和服务端总共发送3个包以确认连接的建立。好比两个人在打电话：
当连接被建立或被终止，交换的报文段只包含TCP头部，而没有数据。
tcp报文头部结构 序号：seq序号，占32位，用来标识从TCP源端向目的端发送的字节流，发起方发送数据时对此进行标记。 确认序号：ack序号，占32位，只有ACK标志位为1时，确认序号字段才有效，确认方ack=发起方seq+1，两端配对。 标志位 ACK：确认序号有效。 FIN：释放一个连接。 RST：重置连接。 SYN：发起一个新连接。 PSH：接收方应该尽快将这个报文交给应用层。 URG：紧急指针（urgent pointer）有效。 第一次握手：客户端要向服务端发起连接请求，首先客户端随机生成一个起始序列号ISN(比如是100)，那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1)，序列号seq=100。
第二次握手：服务端收到客户端发过来的报文后，发现SYN=1，知道这是一个连接请求，于是将客户端的起始序列号100存起来，并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文，回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。
第三次握手：客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文；同时发现SYN=1，知道了服务端同意了这次连接，于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端，报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的，所以这次seq就从101开始，需要注意的是不携带数据的ACK报文是不占据序列号的，所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301，就知道客户端收到序列号为300的报文了，就这样客户端和服务端通过TCP建立了连接。
四次挥手 比如客户端初始化的序列号ISA=100，服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据，服务端在客户端发FIN报文前总共回复了2000个字节的数据。
第一次挥手：当客户端的数据都传输完成后，客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据)，释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000，其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了，但是还可以正常收数据；另外FIN报文段即使不携带数据也要占据一个序列号。
第二次挥手：服务端收到客户端发的FIN报文后给客户端回复确认报文，确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态，而不是立马给客户端发FIN报文，这个状态还要持续一段时间，因为服务端可能还有数据没发完。
第三次挥手：服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文，报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
第四次挥手：客户端收到服务端发的FIN报文后，向服务端发出确认报文，确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接，而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接，所以服务端结束TCP连接的时间要比客户端早一些。</description>
    </item>
    <item>
      <title>正则表达式在go中使用</title>
      <link>https://www.161616.top/go-regular-expression/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-regular-expression/</guid>
      <description>正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具。虽然正则表达式比纯粹的文本匹配效率低，但是它却更灵活。按照它的语法规则，随需构造出的匹配模式就能够从原始文本中筛选出几乎任何你想要得到的字符组合。
Go语言通过regexp（regular expression）标准包为正则表达式提供了官方支持，包名采用regular expression的每个单词的前三个首字母组成。
Go语言的正则表达式实现的是RE2标准，Go语言的正则表达式与其他编程语言之间也有一些小的差异。
正则表达式规则 go语言中regexp包使用 简单来说，Go语言中使用正则表达式只需要两步即可：
解析、编译正则表达式 regexp.MustCompile() 返回一个regexp结构体 根据解析好的规则（结构体形式），从指定字符串中提取需要的信息。如 MatchString() FindAllSubmatch()等 go 1 2 3 4 5 6 7 8 9 10 11 12 13 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;regexp&amp;#34; ) func main() { rege := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`) str := rege.FindAllString(&amp;#34;SLAJDLKAJ192.168.0.1DASDASA1231&amp;#34;, -1) fmt.Println(str) } </description>
    </item>
    <item>
      <title>deepin下安装goland中文字体显示全是方块</title>
      <link>https://www.161616.top/deepin-goland/</link>
      <pubDate>Fri, 19 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/deepin-goland/</guid>
      <description>下载中文字体
bash 1 apt-get install ttf-arphic-uming xfonts-intl-chinese 替换goland的汉化包，两个jar包。</description>
    </item>
    <item>
      <title>Go每日一库 - cobra</title>
      <link>https://www.161616.top/go-cobra/</link>
      <pubDate>Thu, 07 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-cobra/</guid>
      <description>Cobra功能 简单子命令cli 如 kubectl verion kubectl get
自动识别-h，&amp;ndash;help 帮助
更过参考官方手册：https://github.com/spf13/cobra
kubectl get pod --all-namespaces
get 代表命令（command） pod 代表事务（args） --all-namespaces 代表标识（flag） command 代表动作， Args 代表事务， flags 代表动作的修饰符。 使用Cobra 使用cobra需要main.go或和cmd/cmd.go(非固定，根据官方手册说明操作的)，来创建需要添加的命令。
cobra不需要构造函数，只需要创建命令即可
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 rootCmd = &amp;amp;cobra.Command{ Use: &amp;#34;db &amp;#34;, Short: &amp;#34;test1&amp;#34;, Long: `this is a test123`, Run: func(cmd *cobra.Command, args []string) { log.Println(cfgFile, port) }, } func Execute() { if err := rootCmd.</description>
    </item>
    <item>
      <title>Go每日一库 - cronexpr</title>
      <link>https://www.161616.top/cronexpr/</link>
      <pubDate>Thu, 14 Feb 2019 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/cronexpr/</guid>
      <description>包获取：go get -u github.com/gorhill/cronexpr
创建一个定时任务
go 1 expr, err = cron.Parse(&amp;#34;* * * * *&amp;#34;); 获得任务的下次执行时间
go 1 nextTime = expr.Next(now) 完整代码
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;time&amp;#34; cron &amp;#34;github.</description>
    </item>
    <item>
      <title>Go byte与rune区别</title>
      <link>https://www.161616.top/golang-byte-and-rune/</link>
      <pubDate>Wed, 12 Dec 2018 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/golang-byte-and-rune/</guid>
      <description>先看代码
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package main import ( &amp;#34;fmt&amp;#34; ) func main() { var a = &amp;#34;hello world&amp;#34; var b = &amp;#34;中&amp;#34; fmt.Println([]rune(a)) fmt.Println([]rune(b)) fmt.Println([]byte(b)) } go源码中的定义
go 1 2 3 4 5 6 7 8 // byte is an alias for uint8 and is equivalent to uint8 in all ways. It is // used, by convention, to distinguish byte values from 8-bit unsigned // integer values.</description>
    </item>
    <item>
      <title>Go每日一库 - bufio缓冲区的终端输入</title>
      <link>https://www.161616.top/go-bufio/</link>
      <pubDate>Tue, 27 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-bufio/</guid>
      <description>bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象，os.stdin就是实现了这个接口
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package main import ( &amp;#34;bufio&amp;#34; &amp;#34;fmt&amp;#34; &amp;#34;os&amp;#34; ) var buff *bufio.Reader func main() { buff = bufio.NewReader(os.Stdin) str, err := buff.ReadString(&amp;#39;\n&amp;#39;) if err == nil { fmt.Printf(&amp;#34;input was :%s&amp;#34;, str) } } ReadString(byte) 遇到byte后返回，包含已读到的和byte，如果在读到之前遇到错误，返回读取的信息及该错误
在写文件时。可以写入缓冲区来可以提升磁盘性能</description>
    </item>
    <item>
      <title>Go数组排序算法</title>
      <link>https://www.161616.top/go-datasort/</link>
      <pubDate>Wed, 24 Oct 2018 00:00:00 +0000</pubDate>
      <guid>https://www.161616.top/go-datasort/</guid>
      <description>冒泡排序 图 https://www.cnblogs.com/onepixel/articles/7674659.html
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package main import ( &amp;#34;fmt&amp;#34; ) func bubbleSort(slice []int) []int { for n := 0; n &amp;lt;= len(slice); n++ { for i := 1; i &amp;lt; len(slice)-n; i++ { if slice[i] &amp;lt; slice[i-1] { slice[i], slice[i-1] = slice[i-1], slice[i] } } } return slice } func main() { var arr = [.</description>
    </item>
  </channel>
</rss>
