《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()
}



posted @ 2020-03-26 16:52  西*风  阅读(390)  评论(0编辑  收藏  举报