《Go程序设计语言》第一章 源码

fetch.go

// fetch 输出从url获取的内容
package main
import (
        "fmt"
        "io/ioutil"
        "net/http"
        "os"
)

func main() {
        // 获取屏幕输入的URL
        for _, url := range os.Args[1:] {
                resp, err := http.Get(url)// 请求url,获得响应
                if (err != nil) {//处理响应失败情况
                        fmt.Fprint(os.Stderr, "fetch:%v\n", err)
                        os.Exit(1)//进程退出1返回状态码1
                }
                //读取响应的主体内容
                body, err := ioutil.ReadAll(resp.Body)
                //避免资源泄露
                resp.Body.Close()
                //处理读取失败情况
                if (err != nil) {
                        fmt.Fprintf(os.Stderr, "fetch:reading %s:%v\n", url, err)
                        os.Exit(1)
                }
                //打印
                fmt.Printf("%s", body)
        }
}
//执行命令: go run fetch.go http://www.baidu.com

fetchall.go

// fetchall 并发获取url的内容并且报告耗时
package main

import (
        "fmt"
        "io"
        "io/ioutil"
        "net/http"
        "os"
        "time"
)

func main() {
        //获得程序·开始时间
        start := time.Now()
        //创建字符串通道
        ch := make(chan string)
        for _, url := range os.Args[1:] {
                //启动一个goroutine,调用fetch函数,通过通道向该goroutine发信息
                go fetch(url, ch)
        }
        // 接收从ch通道过来的信息
        for range os.Args[1:] {
                fmt.Println(<-ch)
        }
        //打印程序总耗时
        fmt.Printf("%0.2fs elapsed\n", time.Since(start).Seconds())
}

func fetch(url string, ch chan<- string) {
        //获得一个goroutine开始运行的时间
        start := time.Now()
        // 获得url的响应
        resp, err := http.Get(url)
        if (err != nil) {
                ch <- fmt.Sprint(err)
                return
        }
        //通过copy函数读取响应内容,将内容写入到输出流discard进行丢弃,返回字节数nbyte和错误信息
        nbytes, err := io.Copy(ioutil.Discard, resp.Body)
        //避免资源泄露
        resp.Body.Close()
        if (err != nil) {
                ch <- fmt.Sprintf("while reading %s:%v", url, err)
                return
        }
        //大致的获得该goroutine结束的耗时
        secs := time.Since(start).Seconds()
        //通过通道向main传送相关信息
        ch <- fmt.Sprintf("%2fs %7d %s", secs, nbytes, url)
}

/*
go run fetchall.go http://golang.org http://www.baidu.com  http://godoc.org
0.069750s  201483 http://www.baidu.com
0.514788s   11077 http://golang.org
0.766819s    7161 http://godoc.org
0.77s elapsed
*/

server1.go

//server1 是一个迷你回声服务器
package main

import (
        "fmt"
        "log"
        "net/http"
)

func main() {
        //回声请求调用处理函数
        http.HandleFunc("/", handler)
        //监听端口
        log.Fatal(http.ListenAndServe("localhost:8080", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
        //获得请求的url链接,得到请求路径
        fmt.Fprintf(w, "url.path = %q\n", r.URL.Path)
}
/*
1.main函数将一个处理函数和以/开头的url链接在一起,代表所有的url都使用这个处理函数,然后启动服务器监听进入8080端口处的请求

2.一个请求由一个http.Request类型的结构体表示,它包含很多关联的域,其中一个是所请求的URL
  当一个请求到达时,被转交给处理函数,并且从请求的URL提取路径部分,然后使用fmt.Fprintf格式化,然后作为响应发送出去

*/

server2.go

//server2是一个迷你的回声和计数服务器
package main

import (
        "fmt"
        "log"
        "net/http"
        "sync"
)

var mu sync.Mutex //全局计算器锁
var count int //计算器

func main() {
        http.HandleFunc("/", handler)
        http.HandleFunc("/count", counter)
        log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
//处理程序回显请求的URL的路径部分
func handler(w http.ResponseWriter, r *http.Request) {
        mu.Lock()
        count++
        mu.Unlock()
        fmt.Fprintf(w, "url.path=%q\n", r.URL.Path)
}
//回显服务目前为止调用的次数
func counter(w http.ResponseWriter, r *http.Request) {
        mu.Lock()
        fmt.Fprintf(w, "count %d\n", count)
        mu.Unlock()
}

server3.go

// server3 要求处理程序回显http请求
package main

import (
        "fmt"
        "log"
        "net/http"
        "sync"
)

var mu sync.Mutex //全局计算器锁
var count int     //计算器

func main() {
        http.HandleFunc("/", handler)
        http.HandleFunc("/count", counter)
        log.Fatal(http.ListenAndServe("localhost:8080", nil))
}

//处理程序回显请求的URL的路径部分
func handler(w http.ResponseWriter, r *http.Request) {
        mu.Lock()
        count++
        mu.Unlock()

        fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)
        for k, v := range r.Header {
                fmt.Fprintf(w, "Header[%q]=%q\n", k, v)
        }
        fmt.Fprintf(w, "Host=%q\n", r.Host)
        fmt.Fprintf(w, "remoteaddr=%q\n", r.RemoteAddr)
        if err := r.ParseForm(); err != nil {
                log.Print(err)
        }
        for k, v := range r.Form {
                fmt.Fprintf(w, "Form[%q]=%q\n", k, v)
        }
}

//回显服务目前为止调用的次数
func counter(w http.ResponseWriter, r *http.Request) {
        mu.Lock()
        fmt.Fprintf(w, "count %d\n", count)
        mu.Unlock()
}