Golang語言 之網路
Go語言標準庫裡提供的net包,支援基於IP層、TCP/UDP層及更高層面(如HTTP、FTP、SMTP)的網路操作,其中用於IP層的稱為Raw Socket。
net包的Dial()函式用於建立網路連線,函式原型如下:
func Dial(net, addr string) (Conn, error)
其中net引數是網路協議的名字,addr引數是IP地址或域名;如果連線成功,返回連線物件,否則返回error。
目前,Dial()函式支援如下幾種網路協議:"tcp"、"udp"、"ip"、"ip6"等,例如:
conn, err := net.Dial("tcp", "192.168.0.10:2100") // TCP連線 conn, err := net.Dial("udp", "192.168.0.12:975") // UDP連線 conn, err := net.Dial("ip4:icmp", "www.baidu.com") // ICMP連線
在成功連線連線後,可以使用conn的Write()和Read()方法讀寫資料。
實際上,Dial()函式是對DialTCP()、DialUDP()、DialIP()、DialUnix()函式的封裝:
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error) func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err error) func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error)
下面是一個TCP示例程式:
func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) os.Exit(1) } } func readFully(conn net.Conn) ([]byte, error) { defer conn.Close() result := bytes.NewBuffer(nil) var buf [512]byte for { n, err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil, err } } return result.Bytes(), nil } func main() { addr := "127.0.0.1:80" conn, err := net.Dial("tcp", addr) checkError(err) _, err = conn.Write([]byte("GET /api/v3/get HTTP/1.1rnrn")) checkError(err) result, err := readFully(conn) checkError(err) fmt.Println(string(result)) os.Exit(0) }
HTTP協議
Go語言標準庫內建提供了net/http包,涵蓋了HTTP客戶端和服務端的具體實現。
HTTP客戶端
net/http包的Client型別提供瞭如下幾個方法:
func (c *Client) Get(url string) (r *Response, err error)
func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error)
func (c *Client) PostForm(url string, data url.Values) (r *Response, err error)
func (c *Client) Head(url string) (r *Response, err error)
func (c *Client) Do(req *Request) (r *Response, err error)
以GET方法為例:
resp, err := http.Get("http://cre.mix.sina.com.cn/api/v3/get")
if err != nil { fmt.Println("get failed", err) return }
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)
上面這段程式碼請求一個網站首頁,並將其內容列印到標準輸出流中。
如果希望對請求做更多的控制,可以使用DO()方法:
req, err := http.NewRequest("GET", "http://cre.mix.sina.com.cn/api/v3/get", nil)
req.Header.Add("User-Agent", "Go GO")
client := &http.Client{}
resp, err := client.Do(req)
HTTP服務端
使用net/http包提供的下面兩個方法
func ListenAndServe(addr string, handler Handler) error
func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error
ListenAndServe()函式有2個引數,第一個引數addr即監聽地址,第二個引數表示服務端處理程式,通常為空,使用預設的http.DefaultServeMux進行處理。
服務端的業務邏輯使用http.Handle()或http.HandleFunc(),會預設注入http.DefaultServeMux中,如:
http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
http.ListenAndServe(":8001", nil)
RPC協議
在Go中,標準庫提供的net/rpc包實現了PRC協議需要的相關細節,開發者可以很方便地使用該包編寫RPC的服務端和客戶端程式。
json處理
在Web開發領域中,JSON被廣泛用於web服務端程式和客戶端之間的資料通訊。
Go語言內建對JSON的支援,使用encoding/json標準庫,開發者可以輕鬆使用Go程式生成和解析JSON格式的資料。
func Marshal(v interface{}) ([]byte, error)
func Unmarshal(vdata []byte, v interface{}) error
JSON編碼的一個例子:
type Book struct {
Title string
Authors [] string
Publisher string
IsPublished bool
Price float32
}
func main() {
gobook := Book { "Go programming",
[]string { "XuShiwei", "HughLv", "Johnson"}, "isturing.com.cn", true, 9.99,
}
// encode
b, err := json.Marshal(gobook) // 變數b 是一個[]byte型別 if err == nil {
fmt.Println(b)
}
// decode
var book Book
json.Unmarshal(b, &book)
fmt.Println(book)
}
當我們呼叫json.Marshal(gobook)函式時,會遞迴遍歷gobook物件,如果發現gobook這個資料結構實現了json.Marshaler介面且包含有效的值,Marshal()就會呼叫其MarshalJSON()方法將該資料結構生成JSON格式的文字。
Go語言的大多數型別都可以轉化為有效的JSON文字,但channel、complex和函式這幾種型別除外;而對於指標,會轉化為指標所指向的值,如果指標指向的是零值,那麼null將作為轉化後輸出的結果。具體的轉化規則如下:
- 布林值轉化為JSON的bool型別;
- 浮點數和整型轉化為JSON的number型別;
- 字串將以UTF-8編碼轉化為Unicode字符集的字串;
- 陣列和切片轉化為JSON的array型別,但[]byte型別的值會被轉化為Base64編碼後的字串,slice型別的零值會被轉化為null;
- 結構體轉化為JSON的object型別,並且只有結構體中以大寫字母開頭的可被匯出的欄位才會被轉化輸出;
- 轉化一個map型別的資料結構時,該資料的型別必須是map[string] T。