分类 - Go语言四十二章经

Go语言四十二章经    2021-01-27 10:09:44    75    0    0

《Go语言四十二章经》第三十章 OS包

作者:李骁

30.1 启动外部命令和程序

os 包有一个 StartProcess 函数可以调用或启动外部系统命令和二进制可执行文件;它的第一个参数是要运行的进程,第二个参数用来传递选项或参数,第三个参数是含有系统环境基本信息的结构体。

这个函数返回被启动进程的 id(pid),或者启动失败返回错误。

exec 包中也有同样功能的更简单的结构体和函数;主要是 exec.Command(name string, arg ...string) 和 Run()。首先需要用系统命令或可执行文件的名字创建一个 Command 对象,然后用这个对象作为接收器调用 Run()。下面的程序(因为是执行 Linux 命令,只能在 Linux 下面运行)演示了它们的使用:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func main() {
  7. // 1) os.StartProcess //
  8. /*********************/
  9. /* Linux: */
  10. env := os.Environ()
  11. procAttr := &os.ProcAttr{
  12. Env: env,
  13. Files: []*os.File{
  14. os.Stdin,
  15. os.Stdout,
  16. os.Stderr,
  17. },
  18. }
  19. // 1st example: list files
  20. Pid, err := os.StartProcess("/bin/ls", []string{"ls", "-l"}, procAttr)
  21. if err != nil {
  22. fmt.Printf("Error %v starting process!", err) //
  23. os.Exit(1)
  24. }
  25. fmt.Printf("The process id is %v", pid)
  26. }

30.2 os/signal 信号处理

信号处理在平

Go语言四十二章经    2021-01-27 10:09:44    9    0    0

《Go语言四十二章经》第三十一章 文件操作与IO

作者:李骁

31.1 文件系统

对于文件和目录的操作,Go主要在os 提供了的相应函数:

  1. func Mkdir(name string, perm FileMode) error
  2. func Chdir(dir string) error
  3. func TempDir() string
  4. func Rename(oldpath, newpath string) error
  5. func Chmod(name string, mode FileMode) error
  6. func Open(name string) (*File, error) {
  7. return OpenFile(name, O_RDONLY, 0)
  8. }
  9. func Create(name string) (*File, error) {
  10. return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
  11. }
  12. func OpenFile(name string, flag int, perm FileMode) (*File, error) {
  13. testlog.Open(name)
  14. return openFileNolog(name, flag, perm)
  15. }

从上面函数定义中我们可以发现一个情况:那就是os中不同函数打开(创建)文件的操作,最终还是通过OpenFile来实现,而OpenFile由编译器根据系统的情况来选择不同的底层功能来实现,对这个实现细节有兴趣可以根据标准包来仔细了解,这里就不展开讲了。

  1. os.Open(name string) 使用只读模式打开文件;
  2. os.Create(name string) 创建新文件,如文件存在则原文件内容会丢失;
  3. os.OpenFile(name string, flag int, perm FileMode) 这个函数可以指定flagFileMode 。这三个函数都会返回一个文件对象。
  1. Flag
  2. O_RDONLY int = syscall.O_RDONLY // 只读打开文件和os.Open()同义
  3. O_WRONLY int =
Go语言四十二章经    2021-01-27 10:09:44    13    0    0

《Go语言四十二章经》第三十二章 fmt包

作者:李骁

32.1 fmt包格式化I/O

上一章我们有提到fmt格式化I/O,这一章我们就详细来说说。在fmt包,有关格式化输入输出的方法就两大类:Scan 和 Print ,分别在scan.go 和 print.go 文件中。

print.go文件中定义了如下函数:

  1. func Printf(format string, a ...interface{}) (n int, err error)
  2. func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
  3. func Sprintf(format string, a ...interface{}) string
  4. func Print(a ...interface{}) (n int, err error)
  5. func Fprint(w io.Writer, a ...interface{}) (n int, err error)
  6. func Sprint(a ...interface{}) string
  7. func Println(a ...interface{}) (n int, err error)
  8. func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
  9. func Sprintln(a ...interface{}) string

这9个函数,按照两个维度来说明,基本上可以说明白了。当然这两个维度是我个人为了记忆而分,并不是官方的说法。

一:如果把"Print"理解为核心关键字,那么后面跟的后缀有"f"和"ln"以及"",着重的是内容输出的结果;

如果后缀是"f", 则指定了format
如果后缀是"ln", 则有换行符

  1. PrintlnFprintlnSprintln 输出内容时会加上换行符;
  2. PrintFprintSprint 输出内容时不加上换行符;
  3. PrintfFprintfSprintf 按照指定格式化文本输出内容。
Go语言四十二章经    2021-01-27 10:09:44    16    0    0

《Go语言四十二章经》第三十三章 Socket网络

作者:李骁

33.1 Socket基础知识

tcp/udp、ip构成了网络通信的基石,tcp/ip是面向连接的通信协议,要求建立连接时进行3次握手确保连接已被建立,关闭连接时需要4次通信来保证客户端和服务端都已经关闭,也就是我们常说的三次握手,四次挥手。在通信过程中还有保证数据不丢失,在连接不畅通时还需要进行超时重试等等。

socket就是封装了这一套基于tcp/udp/ip协议细节,提供了一系列套接字接口进行通信。

我们知道Socket有两种:TCP Socket和UDP Socket,TCP和UDP是协议,而要确定一个进程的需要三元组,还需要IP地址和端口。

  • IPv4地址

目前的全球因特网所采用的协议族是TCP/IP协议。IP是TCP/IP协议中网络层的协议,是TCP/IP协议族的核心协议。目前主要采用的IP协议的版本号是4(简称为IPv4),IPv4的地址位数为32位,也就是最多有2的32次方的网络设备可以联到Internet上。

地址格式类似这样:127.0.0.1

  • IPv6地址

IPv6是新一版本的互联网协议,也可以说是新一代互联网的协议,它是为了解决IPv4在实施过程中遇到的各种问题而被提出的,IPv6采用128位地址长度,几乎可以不受限制地提供地址。在IPv6的设计过程中除了一劳永逸地解决了地址短缺问题以外,还考虑了在IPv4中解决不好的其它问题,主要有端到端IP连接、服务质量(QoS)、安全性、多播、移动性、即插即用等。

地址格式类似这样:2002:c0e8:82e7:0:0:0:c0e8:82e7

33.2 TCP 与 UDP

Go是自带runtime的跨平台编程语言,Go中暴露给语言使用者的tcp socket api是建立OS原生tcp socket接口之上的,所以在使用上相对简单。

TCP Socket

建立网络连接过程:TCP连接的建立需要经历客户端和服务端的三次握手的过程。Go 语言net包封装了系列API,在TCP连接中,服务端是一个标准的Listen + Accept的结构,而在客户端Go语言使用net.Dial或

Go语言四十二章经    2021-01-27 10:09:44    10    0    0

《Go语言四十二章经》第三十四章 命令行 flag 包

作者:李骁

34.1 命令行

写命令行程序时需要对命令参数进行解析,这时我们可以使用os库。os可以通过变量Args来获取命令参数,os.Args返回一个字符串数组,其中第一个参数就是执行文件本身。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func main() {
  7. fmt.Println(os.Args)
  8. }

编译执行后执行

  1. $ ./cmd -user="root"
  2. [./cmd -user=root]

这种方式操作起来要自己封装,比较费时费劲。

34.2 flag包

Go提供了flag库,可以很方便的操作命名行参数,下面介绍下flag的用法。

几个概念:

1)命令行参数(或参数):是指运行程序提供的参数

2)已定义命令行参数:是指程序中通过flag.Xxx等这种形式定义了的参数

3)非flag(non-flag)命令行参数(或保留的命令行参数):先可以简单理解为flag包不能解析的参数

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. )
  7. var (
  8. h, H bool
  9. v bool
  10. q *bool
  11. D string
  12. Conf string
  13. )
  14. func init() {
  15. flag.BoolVar(&h, "h", false, "帮助信息")
  16. flag.BoolVar(&h, "H", false, "帮助信息")
  17. flag.BoolVar(&v, "v", false, "显示版本号")
  18. //
  19. flag.StringVar(&D, "D", "deamon", "set descripton ")
  20. flag.StringVar(&Conf, "Conf", "/dev/conf/cli.conf", "set Conf filename ")
  21. // 另一种绑定方式
  22. q = flag.Bool("q", false, "退出程序")
  23. // 像flag.Xxx函数格式都是一样的
Go语言四十二章经    2021-01-27 10:09:44    11    0    0

《Go语言四十二章经》第三十五章 模板

作者:李骁

Printf也可以做到输出格式化,当然,对于简单的例子来说足够了,但是我们有时候还是需要复杂的输出格式,甚至需要将格式化代码分离开来。这时,可以使用text/template和html/template。

Go 官方库提供了两个模板库: text/template 和 html/template 。这两个库类似,当需要输出html格式的代码时需要使用 html/template。

35.1 text/template

所谓模板引擎,则将模板和数据进行渲染的输出格式化后的字符程序。对于Go,执行这个流程大概需要三步。

  • 创建模板对象
  • 加载模板
  • 执行渲染模板

其中最后一步就是把加载的字符和数据进行格式化。

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "text/template"
  6. )
  7. const templ = `
  8. {{range .}}----------------------------------------
  9. Name: {{.Name}}
  10. Price: {{.Price | printf "%4s"}}
  11. {{end}}`
  12. var report = template.Must(template.New("report").Parse(templ))
  13. type Book struct {
  14. Name string
  15. Price float64
  16. }
  17. func main() {
  18. Data := []Book{{"《三国演义》", 19.82}, {"《儒林外史》", 99.09}, {"《史记》", 26.89}}
  19. if err := report.Execute(os.Stdout, Data); err != nil {
  20. log.Fatal(err)
  21. }
  22. }
  1. 程序输出:
  2. ----------------------------------------
  3. Name: 《三国演义》
  4. Price: %!s(float64=19.82)
  5. -------------------------------------
Go语言四十二章经    2021-01-27 10:09:44    65    0    0

《Go语言四十二章经》第三十六章 net/http包

作者:李骁

在Go中,搭建一个http server简单到令人难以置信。只需要引入net/http包,写几行代码,一个http服务器就可以正常运行并接受访问请求。

下面就是Go最简单的http服务器:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. func myfunc(w http.ResponseWriter, r *http.Request) {
  7. fmt.Fprintf(w, "hi")
  8. }
  9. func main() {
  10. http.HandleFunc("/", myfunc)
  11. http.ListenAndServe(":8080", nil)
  12. }

访问 http://localhost:8080/ , 我们可以看到网页输出"hi" !

下面我们通过分析net/http的源代码,来深入理解这个包的实现原理。在net/http源代码中,我们可以深深体会到Go语言的接口设计哲学,这个包主要有4个文件,分别是:

client.go

server.go

request.go

response.go

我们知道有http Request 请求和 http Response 响应,以及client和server,我们先从这四个方面讲讲net/http包:

36.1 Request

http Request请求是由客户端发出的消息, 用来使服务器执行动作.发出的消息包括起始行, Headers, Body。

在net/http包中,request.go文件定义了结构:

  1. type Request struct
  2. 代表客户端给服务器端发送的一个请求或者是服务端收到的一个请求,但是服务器端和客户端使用Request时语义区别很大。
  3. // 利用指定的method, url以及可选的body返回一个新的请求.如果body参数实现了
  4. // io.Closer接口,Request返回值的Body 字段会被设置为body,并会被Client
  5. // 类型的Do、Post和PostForm方法以及Transport.RoundTrip
Go语言四十二章经    2021-01-27 10:09:44    19    0    0

《Go语言四十二章经》第三十七章 context包

作者:李骁

37.1 context包

在Go中,每个请求的request在单独的goroutine中进行,处理一个request也可能涉及多个goroutine之间的交互。一个请求衍生出的各个 goroutine 之间需要满足一定的约束关系,以实现一些诸如有效期,中止routine树,传递请求全局变量之类的功能。于是Go为我们提供一个解决方案,标准context包。使用context可以使开发者方便的在这些goroutine之间传递request相关的数据、取消goroutine的signal或截止时间等。

每个goroutine在执行之前,都要先知道程序当前的执行状态,通常将这些执行状态封装在一个Context变量中,传递给要执行的goroutine中。上下文则几乎已经成为传递与请求同生存周期变量的标准方法。在网络编程下,当接收到一个网络请求Request,处理Request时,我们可能需要开启不同的goroutine来获取数据与逻辑处理,即一个请求Request,会在多个goroutine中处理。而这些goroutine可能需要共享Request的一些信息;同时当Request被取消或者超时的时候,所有从这个Request创建的所有goroutine也应该被结束。

context包不仅实现了在程序单元之间共享状态变量的方法,同时能通过简单的方法,使我们在被调用程序单元的外部,通过设置ctx变量值,将过期或撤销这些信号传递给被调用的程序单元。若存在A调用B的API,B再调用C的API,若A调用B取消,那也要取消B调用C,通过在A, B, C的API调用之间传递Context,以及判断其状态。

Context结构

  1. // Context包含过期,取消信号,request值传递等,方法在多个goroutine中协程安全
  2. type Context interface {
  3. // Done 方法在context被取消或者超时返回一个close的channel
  4. Done() <-chan struct{}
  5. Err() error
  6. // Deadline 返回con
Go语言四十二章经    2021-01-27 10:09:44    24    0    0

《Go语言四十二章经》第三十八章 Json数据格式

作者:李骁

38.1 序列化与反序列化

数据结构要在网络中传输或保存到文件,就必须对其编码和解码;目前存在很多编码格式:Json,XML,Gob,Google 缓冲协议等等。Go 语言支持所有这些编码格式。

结构可能包含二进制数据,如果将其作为文本打印,那么可读性是很差的。另外结构内部可能包含匿名字段,而不清楚数据的用意。

通过把数据转换成纯文本,使用命名的字段来标注,让其具有可读性。这样的数据格式可以通过网络传输,而且是与平台无关的,任何类型的应用都能够读取和输出,不与操作系统和编程语言的类型相关。

下面是一些术语说明:

  • 数据结构 --> 指定格式 = 序列化 或 编码(传输之前)
  • 指定格式 --> 数据格式 = 反序列化 或 解码(传输之后)

序列化是在内存中把数据转换成指定格式(data -> string),反之亦然(string -> data structure)

编码也是一样的,只是输出一个数据流(实现了 io.Writer 接口);解码是从一个数据流(实现了 io.Reader)输出到一个数据结构。

  1. Json.Marshal() 的函数签名是 func Marshal(v interface{}) ([]byte, error)

出于安全考虑,在 web 应用中最好使用 Json.MarshalforHTML() 函数,其对数据执行HTML转码,所以文本可以被安全地嵌在 HTML

Go语言四十二章经    2021-01-27 10:09:44    37    0    0

《Go语言四十二章经》第三十九章 Mysql数据库

作者:李骁

39.1 database/sql包

Go 提供了database/sql包用于对SQL数据库的访问,作为操作数据库的入口对象sql.DB,主要为我们提供了两个重要的功能:

  • sql.DB 通过数据库驱动为我们提供管理底层数据库连接的打开和关闭操作.
  • sql.DB 为我们管理数据库连接池

需要注意的是,sql.DB表示操作数据库的抽象访问接口, 而非一个数据库连接对象;它可以根据driver打开关闭数据库连接,管理连接池。正在使用的连接被标记为繁忙,用完后回到连接池等待下次使用。所以,如果你没有把连接释放回连接池,会导致过多连接使系统资源耗尽。

导入mysql数据库驱动

  1. import (
  2. "database/sql"
  3. _ "github.com/go-sql-driver/mysql"
  4. )

通常来说,不应该直接使用驱动所提供的方法,而是应该使用 sql.DB,因此在导入 mysql 驱动时,这里使用了匿名导入的方式(在包路径前添加 _),当导入了一个数据库驱动后,此驱动会自行初始化并注册自己到Go的database/sql上下文中,因此我们就可以通过 database/sql 包提供的方法访问数据库了。

39.2 Mysql数据库操作

我们先建立表结构:

  1. CREATE TABLE t_article_cate (
  2. `cid` int(10) NOT NULL AUTO_INCREMENT,
  3. `cname` varchar(60) NOT NULL,
  4. `ename` varchar(100),
  5. `cateimg` varchar(255),
  6. `addtime` int(10) unsigned NOT NULL DEFAULT '0',
  7. `publishtime` int(10) unsigned NOT NULL DEFAULT '0',
  8. `scope` int(10) unsigned NOT NULL DEFAULT '10000',
  9. `status` tinyint(1) unsigned NOT NULL
4/5