iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 12
1
Software Development

Golang入門到進階實戰系列 第 12

Day12 網路通訊協定

Requests for comments(RFC)

RFC(Request For Comments)-意即“請求註解”,包含了關於Internet的幾乎所有重要的文字資料。如果你想成為網絡方面的專家,那麽RFC無疑是最重要也是最經常需要用到的資料之一,所以RFC享有網絡知識聖經之美譽。通常,當某家機構或團體開發出了一套標準或提出對某種標準的設想,想要征詢外界的意見時,就會在Internet上發放一份RFC,對這一問題感興趣的人可以閱讀該RFC並提出自己的意見;絕大部分網絡標準的指定都是以RFC的形式開始,經過大量的論證和修改過程,由主要的標準化組織所指定的,但在RFC中所收錄的文件並不都是正在使用或為大家所公認的,也有很大一部分只在某個局部領域被使用或並沒有被采用,一份RFC具體處於什麽狀態都在文件中作了明確的標識
RFC由一系列草案組成,起始於1969年(第一個RFC文檔發布於1969年4月7日,參見“RFC30年”,RFC2555”),RFC文檔是一系列關於Internet(早期為ARPANET)的技術資料匯編。這些文檔詳細討論了計算機網絡的方方面面,重點在網絡協議,進程,程序,概念以及一些會議紀要,意見,各種觀點等。
“RFC編輯者”是RFC文檔的出版者,它負責RFC最終文檔的編輯審訂。“RFC編輯者”也保留有RFC的主文件,稱為RFC索引,用戶可以在線檢索。在RFC近30年的歷史中,“RFC編輯者”一直由約翰•普斯特爾(Jon Postel)來擔任,而現在“RFC編輯者”則由一個工作小組來擔任,這個小組受到“因特網社團”(Internet Society)的支助。
RFC編輯者負責RFC以及RFC的整體結構文檔,並維護RFC的索引。Internet協議族的文檔部分(由Internet工程委員會“因特網工程師任務組”IETF以及IETF 下屬的“因特網工程師指導組”IESG 定義),也做為RFC文檔出版。因此,RFC在Internet相關標準中有著重要的地位。
RFC編輯者的職責是由Internet 中的大家提議形成的,所出版的語言也就和Internet一樣。IETF和ISOC是代表了世界各地的國際性組織,英語是IETF的第一工作語言,也是IETF的正式出版語言。RFC 2026 "The Internet Standards Process -- Revision 3" 允許RFC翻譯成其他不同的語言。但是不能保證其翻譯版本是否正確。因此,RFC編輯不對非英語的版本負責,而只是指明了哪裏有非英語的版本,將這些信息列在WEB頁上。

encode & decode

為了讓某個數據結構能夠在網路上傳輸,發送者必須在傳輸前將數據結構被編碼成符合RFCs規範的格式,接收者則是在收到資料後使用RFCs格式解碼,還原出原始的資料結構。

Go語言已經內建了許多的RFCs包,這裡介紹常用的encoding/json和net/http。

net/http

  • http包提供了HTTP客戶端和服務端的實現。
  • 透過Get、Head、Post和PostForm函數可以發送出HTTP/HTTPS請求。

Requests

舉例,使用http.Get函數對www.google.com發送get請求。

package main
import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    response, err := http.Get("http://www.google.com")
    if err != nil {
    // handle error
    }
    // 使用完後必須關閉reponse主體
    defer response.Body.Close()

    body, _ := ioutil.ReadAll(response.Body)
    fmt.Println(string(body))
}

創建Web service

package main

import (
    "net/http"
)

func SayHello(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello World!"))
}

func main() {
    http.HandleFunc("/hello", SayHello)
    http.ListenAndServe(":8001", nil)

}

透過net/http包創建一個web service,首先我們調用Http.HandleFunc按順序設置幾件事:

  • 調用了DefaultServerMux的handleFunc
  • 調用了DefaultServerMux的Handle
  • 在DefaultServeMux的map[string]muxEntry中增加對應的handler和路由規則

其次調用http.ListenAndServe(":8001",nil),按順序做了幾件事:

  • 實例化Server

  • 調用Server的ListenAndServe()

  • 調用net.Listen(“tcp”, addr)監聽端口

  • 啟動一個for循環,在循環體中Accept請求

  • 對每個請求實例化一個Conn,並且開啟一個goroutine為這個請求進行服務go c.serve()

  • 讀取每個請求的內容w, err := c.readRequest()

  • 判斷header是否為空,如果沒有設置handler(這個例子就沒有設置handler),handler就設置為DefaultServeMux

  • 調用handler的ServeHttp

  • 在這個例子中,下面就進入到DefaultServerMux.ServeHttp

  • 根據request選擇handler,並且進入到這個handler的ServeHTTP

    mux.handler(r).ServeHTTP(w, r)

  • 選擇handler:

A. 判斷是否有路由能滿足這個request(循環遍歷ServerMux的muxEntry)
B. 如果有路由滿足,調用這個路由handler的ServeHttp
C. 如果沒有路由滿足,調用NotFoundHandler的ServeHttp

json

JavaScript對象表示法(JSON)是一種用於發送和接收結構化信息的標準協議。在類似的協議中,JSON併不是唯一的一個標準協議。 XML(§7.14)、ASN.1和Google的Protocol Buffers都是類似的協議,併且有各自的特色,但是由於簡潔性、可讀性和流行程度等原因,JSON是應用最廣泛的一個。
Go語言對於這些標準格式的編碼和解碼都有良好的支持,由標準庫中的encoding/json、encoding/xml、encoding/asn1等包提供支持(譯註:Protocol Buffers的支持由 github.com/golang/protobuf 包提供),併且這類包都有着相似的API接口。本節,我們將對重要的encoding/json包的用法做個概述。
JSON是對JavaScript中各種類型的值——字符串、數字、布爾值和對象——Unicode本文編碼。它可以用有效可讀的方式表示第三章的基礎數據類型和本章的數組、slice、結構體和map等聚合數據類型。

基本的JSON類型有數字(十進製或科學記數法)、布爾值(true或false)、字符串,其中字符串是以雙引號包含的Unicode字符序列,支持和Go語言類似的反斜槓轉義特性,不過JSON使用的是\Uhhhh轉義數字來表示一個UTF-16編碼(譯註:UTF-16和UTF-8一樣是一種變長的編碼,有些Unicode碼點較大的字符需要用4個字節表示;而且UTF-16還有大端和小端的問題),而不是Go語言的rune類型。
這些基礎類型可以通過JSON的數組和對象類型進行遞歸組合。一個JSON數組是一個有序的值序列,寫在一個方括號中併以逗號分隔;一個JSON數組可以用於編碼Go語言的數組和slice。一個JSON對象是一個字符串到值的映射,寫成以繫列的name:value對形式,用花括號包含併以逗號分隔;JSON的對象類型可以用於編碼Go語言的map類型(key類型是字符串)和結構體。例如:

boolean         true
number          -273.15
string          "She said \"Hello, BF\""
array           ["gold", "silver", "bronze"]
object          {"year": 1980,
                 "event": "archery",
                 "medals": ["gold", "silver", "bronze"]}

JSON 套件裡面透過 Marshal 函數來將數據處理成 JSON 字串

func Marshal(v interface{}) ([]byte, error)

透過 Unmarshal 將 JSON 字串處理成對應的結構

func Unmarshal(data []byte, v interface{}) error

編碼

package main

import (
    "encoding/json"
    "fmt"
)

type Student struct {
    Id     int
    Name   string
    Gender bool
    Age    int
}

func main() {
    student := Student{
        Id:     1,
        Name:   "zhao",
        Gender: true,
        Age:    11,
    }

    fmt.Println(student)
    out, err := json.Marshal(student)
    if err != nil {
        fmt.Println("json marsha1 error")
    }
    fmt.Printf("%s\n", out)
}

編碼輸出

{1 zhao true 11}
{"Id":1,"Name":"zhao","Gender":true,"Age":11}

解碼

package main

import (
	"encoding/json"
	"fmt"
)

type Student struct {
	Id     int
	Name   string
	Gender bool
	Age    int
}

func main() {
	jsonStr := `{"Id":1,"Name":"zhao","Gender":true,"Age":11}`
	fmt.Println(jsonStr)
	var s Student
	err := json.Unmarshal([]byte(jsonStr), &s)
	if err != nil {
		fmt.Println("json unmarshal error: ", err)
	}
	fmt.Println(s)
}

解碼輸出

{"Id":1,"Name":"zhao","Gender":true,"Age":11}
{1 zhao false 11}

上一篇
Day11 Go語言編碼規範
下一篇
Day 13 I/O操作
系列文
Golang入門到進階實戰30

尚未有邦友留言

立即登入留言