<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          go語(yǔ)言中的socket和http

          共 6156字,需瀏覽 13分鐘

           ·

          2024-04-11 09:33

          c2a937b656f4a0060def1827a5a7bcd5.webp

          【摘要】 Socket 編程以前我們使用Socket編程時(shí),會(huì)按照如下步驟展開。(1) 建立Socket:使用socket()函數(shù)。(2) 綁定Socket:使用bind()函數(shù)。(3) 監(jiān)聽:使用listen()函數(shù)。或者連接:使用connect()函數(shù)。(4) 接受連接:使用accept()函數(shù)。(5) 接收:使用receive()函數(shù)。或者發(fā)送:使用send()函數(shù)。Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)對(duì)此過程進(jìn)行...

          Socket 編程

          以前我們使用Socket編程時(shí),會(huì)按照如下步驟展開。
          (1) 建立Socket:使用socket()函數(shù)。
          (2) 綁定Socket:使用bind()函數(shù)。
          (3) 監(jiān)聽:使用listen()函數(shù)。或者連接:使用connect()函數(shù)。
          (4) 接受連接:使用accept()函數(shù)。
          (5) 接收:使用receive()函數(shù)。或者發(fā)送:使用send()函數(shù)。
          Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)對(duì)此過程進(jìn)行了抽象和封裝。無(wú)論我們期望使用什么協(xié)議建立什么形式的連接,都只需要調(diào)用net.Dial()即可。

          Dial()函數(shù)

          Dial()函數(shù)的原型如下:

              func Dial(net, addr string) (Conn, error) 

          其中net參數(shù)是網(wǎng)絡(luò)協(xié)議的名字,addr參數(shù)是IP地址或域名,而端口號(hào)以“:”的形式跟隨在地址或域名的后面,端口號(hào)可選。如果連接成功,返回連接對(duì)象,否則返回error。

          TCP鏈接:
          conn, err := net.Dial(“tcp”, “192.168.0.10:2100”)
          UDP鏈接:
          conn, err := net.Dial(“udp”, “192.168.0.12:975”)
          ICMP鏈接:
          conn, err := net.Dial(“ip4:icmp”, “www.baidu.com”)
          ICMP鏈接
          conn, err := net.Dial(“ip4:1”, “10.0.0.3”)
          鏈接查看協(xié)議編號(hào)的含義:http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml。
          目前,Dial()函數(shù)支持如下幾種網(wǎng)絡(luò)協(xié)議:“tcp”、“tcp4”(僅限IPv4)、“tcp6”(僅限IPv6)、“udp”、“udp4”(僅限IPv4)、“udp6”(僅限IPv6)、“ip”、“ip4”(僅限IPv4)和"ip6"
          (僅限IPv6)。

          在成功建立連接后,我們就可以進(jìn)行數(shù)據(jù)的發(fā)送和接收。發(fā)送數(shù)據(jù)時(shí),使用conn的Write()成員方法,接收數(shù)據(jù)時(shí)使用Read()方法。

          ICMP示例程序

          下面我們實(shí)現(xiàn)這樣一個(gè)例子:我們使用ICMP協(xié)議向在線的主機(jī)發(fā)送一個(gè)問候,并等待主機(jī)返回。

              package main 
          import (
          "net"
          "os"
          "bytes"
          "fmt"
          )
          func main() {
          if len(os.Args) != 2 {
          fmt.Println("Usage: ", os.Args[0], "host")
          os.Exit(1)
          }
          service := os.Args[1]
          conn, err := net.Dial("ip4:icmp", service)
          checkError(err)
          var msg [512]byte
          msg[0] = 8 // echo
          msg[1] = 0 // code 0
          msg[2] = 0 // checksum
          msg[3] = 0 // checksum
          msg[4] = 0 // identifier[0]
          msg[5] = 13 //identifier[1]
          msg[6] = 0 // sequence[0]
          msg[7] = 37 // sequence[1]
          len := 8
          check := checkSum(msg[0:len])
          msg[2] = byte(check >> 8)
          msg[3] = byte(check & 255)
          _, err = conn.Write(msg[0:len])
          checkError(err)
          _, err = conn.Read(msg[0:])
          checkError(err)
          fmt.Println("Got response")
          if msg[5] == 13 {
          fmt.Println("Identifier matches")
          }
          if msg[7] == 37 {
          fmt.Println("Sequence matches")
          }
          os.Exit(0)
          }
          func checkSum(msg []byte) uint16 {
          sum := 0
          // 先假設(shè)為偶數(shù)
          for n := 1; n <len(msg)-1; n += 2 {
          sum += int(msg[n])*256 + int(msg[n+1])
          }
          sum = (sum >> 16) + (sum & 0xffff)
          sum += (sum >> 16)
          var answer uint16 = uint16(^sum)
          return answer
          }
          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
          }

          執(zhí)行結(jié)果如下:
          $ go build icmptest.go
          $ ./icmptest www.baidu.com
          Got response
          Identifier matches
          Sequence matches

          TCP示例程序

          下面我們建立TCP鏈接來(lái)實(shí)現(xiàn)初步的HTTP協(xié)議,通過向網(wǎng)絡(luò)主機(jī)發(fā)送HTTP Head請(qǐng)求,讀取網(wǎng)絡(luò)主機(jī)返回的信息

              package main 
          import (
          "net"
          "os"
          "bytes"
          "fmt"
          )
          func main() {
          if len(os.Args) != 2 {
          fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0])
          os.Exit(1)
          }
          service := os.Args[1]

          conn, err := net.Dial("tcp", service)
          checkError(err)
          _, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
          checkError(err)
          result, err := readFully(conn)
          checkError(err)
          fmt.Println(string(result))
          os.Exit(0)
          }
          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
          }

          執(zhí)行這段程序并查看執(zhí)行結(jié)果:
          $ go build simplehttp.go
          $ ./simplehttp qbox.me:80
          HTTP/1.1 301 Moved Permanently
          Server: nginx/1.0.14
          Date: Mon, 21 May 2012 03:15:08 GMT
          Content-Type: text/html
          Content-Length: 184
          Connection: close
          Location: https://qbox.me/

          HTTP 編程

          HTTP(HyperText Transfer Protocol,超文本傳輸協(xié)議)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議,定義了客戶端和服務(wù)端之間請(qǐng)求與響應(yīng)的傳輸標(biāo)準(zhǔn)。
          Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)內(nèi)建提供了net/http包,涵蓋了HTTP客戶端和服務(wù)端的具體實(shí)現(xiàn)。使用net/http包,我們可以很方便地編寫HTTP客戶端或服務(wù)端的程序。

          HTTP客戶端

          Go內(nèi)置的net/http包提供了最簡(jiǎn)潔的HTTP客戶端實(shí)現(xiàn),

          基本方法

          net/http包的Client類型提供了如下幾個(gè)方法,讓我們可以用最簡(jiǎn)潔的方式實(shí)現(xiàn) HTTP 請(qǐng)求:

              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) (resp *Response, err error)

          http.Get()
          要請(qǐng)求一個(gè)資源,只需調(diào)用http.Get()方法(等價(jià)于http.DefaultClient.Get())即可,示例代碼如下:

              resp, err := http.Get("http://example.com/") 
          if err != nil {
          // 處理錯(cuò)誤 ...
          return
          }
          defer resp.Body.close()
          io.Copy(os.Stdout, resp.Body)

          http.Post()
          要以POST的方式發(fā)送數(shù)據(jù),也很簡(jiǎn)單,只需調(diào)用http.Post()方法并依次傳遞下面的3個(gè)參數(shù)即可:
          ? 請(qǐng)求的目標(biāo) URL
          ? 將要 POST 數(shù)據(jù)的資源類型(MIMEType)
          ? 數(shù)據(jù)的比特流([]byte形式)
          下面的示例代碼演示了如何上傳一張圖片:

              resp, err := http.Post("http://example.com/upload", "image/jpeg", &imageDataBuf) 
          if err != nil {
          // 處理錯(cuò)誤
          return
          }
          if resp.StatusCode != http.StatusOK {
          // 處理錯(cuò)誤
          return
          }

          http.PostForm()
          http.PostForm()方法實(shí)現(xiàn)了標(biāo)準(zhǔn)編碼格式為application/x-www-form-urlencoded的表單提交。下面的示例代碼模擬HTML表單提交一篇新文章:

              resp, err := http.PostForm("http://example.com/posts", url.Values{"title": 
          {"article title"}, "content": {"article body"}})
          if err != nil {
          // 處理錯(cuò)誤
          return
          }

          ? **http.Head() **
          HTTP 中的 Head 請(qǐng)求方式表明只請(qǐng)求目標(biāo) URL 的頭部信息,即 HTTP Header 而不返回 HTTP Body。Go 內(nèi)置的 net/http 包同樣也提供了 http.Head() 方法,該方法同 http.Get() 方法一樣,只需傳入目標(biāo) URL 一個(gè)參數(shù)即可。下面的示例代碼請(qǐng)求一個(gè)網(wǎng)站首頁(yè)的 HTTP Header信息:

              resp, err := http.Head("http://example.com/") 

          ? *(http.Client).Do()
          在多數(shù)情況下,http.Get()和http.PostForm() 就可以滿足需求,但是如果我們發(fā)起的HTTP 請(qǐng)求需要更多的定制信息,我們希望設(shè)定一些自定義的 Http Header 字段,比如:
          ? 設(shè)定自定義的"User-Agent",而不是默認(rèn)的 “Go http package”
          ? 傳遞 Cookie
          此時(shí)可以使用net/http包http.Client對(duì)象的Do()方法來(lái)實(shí)現(xiàn):

              req, err := http.NewRequest("GET", "http://example.com", nil) 
          // ...
          req.Header.Add("User-Agent", "Gobook Custom User-Agent")
          // ...
          client := &http.Client{ //... }
          resp, err := client.Do(req)
          // ...


          鏈接:https://bbs.huaweicloud.com/blogs/422710

          版權(quán)歸華為云社區(qū) 原作者所有,侵刪)

          瀏覽 43
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  三级黄视频 | 狠狠狠狠狠狠狠狠狠狠狠狠狠狠 | 超碰操网| 久久久性爱 | 影音先锋久久久久久 |