日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

golang微服务网关一:网络基础知识扫盲(温故而知新)

發布時間:2023/12/15 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 golang微服务网关一:网络基础知识扫盲(温故而知新) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

golang微服務網關之網絡基礎知識

面試中被面試官經常問到的一些關于tcp網絡知識問題 今天依依給大家分析下(毫無保留分享:)

三次握手
四次揮手
為啥time_wait需要等待2MSL?
為啥會出現大量的close_wait?
什么時候會出現FIN-WAIT?
TCP為啥需要流量控制?
如何調整網絡負載?
tcp為啥需要擁塞控制?
慢開始和擁塞避免?
快速重傳和快速恢復?
為什么出現粘包/拆包?

為啥time_wait需要等待2MSL?

1,MSL:Maximum Segment Lifetime,30秒-1分鐘

2,保證TCP協議的全雙工連接能夠可靠關閉

3,保證這次連接的重復數據段從網絡中消失

為啥會出現大量的close_wait?

1,首先close_wait一般書現在被動方關閉

2,并發請求太多導致

3,被動關閉方未及時釋放端口資源導致

CLOSE_WAIT產生原因
  close_wait是被動關閉連接是形成的,根據TCP狀態機,服務器端收到客戶端發送的FIN,TCP協議棧會自動發送ACK,鏈接進入close_wait狀態。但如果服務器端不執行socket的close()操作,狀態就不能由close_wait遷移到last_ack,則系統中會存在很多close_wait狀態的連接;

說白的就是并發可能有點大,io不能及時切換過去,I/O線程被意外阻塞,I/O操作處理不及時,鏈路不能被及時釋放

TCP為啥需要流量控制?

如何調整網絡負載,tcp為啥需要擁塞控制?

慢開始和擁塞避免

快速重傳和快速恢復

所謂慢開始,tcp剛開始一點點傳遞試探一下網絡的承受能力,以免擾亂網絡通道的秩序

上圖中,圖標3處遇到網絡擁塞,就把擁塞的窗口直接降為1了,然后重新開始慢開始,一點點遞增

為了優化慢開始所以對算法進行了優化:快重傳和快恢復

快速重傳;當收到3個重復ACK 執行快重傳:

會把當前擁塞窗口降為原來的一般。然后把擁塞避免的預值降為原來的一半,進入一個快速恢復的階段

快速恢復:因為受到3次重復ack,丟包,只要是在這個階段丟的包,會重復發送一遍,直到把所有丟失的包重新發送完畢后就會退出快速恢復階段,

然后進入擁塞避免階段

為什么出現粘包/拆包?

上圖:

發送方由應用程序發送應用的報文,根據應用數據報文大小的不同,它會占用2個或者1個,應用的數據實際會發送到tcp的緩沖區里面(發送緩沖區)。真正發送是由linux內核走tcp連接發送;

tcp根據緩沖區大小來決定是否要粘包,粘包:多次請求合并到一個tcp報文中,拆包:一次請求拆到多個tcp報文里面,至于數據如何被包裝都是由tcp底層去完成的。

因為我運用的其實是應用層,不需要關心它的細節,數據會流入接收方的接收緩沖區,接收方通過socket的reverve方法去獲取到數據。

我們是在應用層通過socket 直接從bufer緩沖區拿取數據

如何獲取完整應用的數據報文?

如何獲取完整的數據報文?

實例代碼:

package unpack

import (
    "encoding/binary"
    "errors"
    "io"
)

const Msg_Header = "12345678"

func Encode(bytesBuffer io.Writer, content string) error {
    //msg_header+content_len+content
    //8+4+content_len
    if err := binary.Write(bytesBuffer, binary.BigEndian, []byte(Msg_Header)); err != nil {
        return err
    }
    clen := int32(len([]byte(content)))
    if err := binary.Write(bytesBuffer, binary.BigEndian, clen); err != nil {
        return err
    }
    if err := binary.Write(bytesBuffer, binary.BigEndian, []byte(content)); err != nil {
        return err
    }
    return nil
}

func Decode(bytesBuffer io.Reader) (bodyBuf []byte, err error) {
    MagicBuf := make([]byte, len(Msg_Header))
    if _, err = io.ReadFull(bytesBuffer, MagicBuf); err != nil {
        return nil, err
    }
    if string(MagicBuf) != Msg_Header {
        return nil, errors.New("msg_header error")
    }

    lengthBuf := make([]byte, 4)
    if _, err = io.ReadFull(bytesBuffer, lengthBuf); err != nil {
        return nil, err
    }

    length := binary.BigEndian.Uint32(lengthBuf)
    bodyBuf = make([]byte, length)
    if _, err = io.ReadFull(bytesBuffer, bodyBuf); err != nil {
        return nil, err
    }
    return bodyBuf, err
}

D:gocode1.14.3gocodegateway_demodemoaseunpackunpackcodec.go

package main

import (
    "fmt"
    "github.com/e421083458/gateway_demo/demo/base/unpack/unpack"
    "net"
)

func main() {
    conn, err := net.Dial("tcp", "localhost:9090")
    defer conn.Close()
    if err != nil {
        fmt.Printf("connect failed, err : %v
", err.Error())
        return
    }
    unpack.Encode(conn, "hello world 0!!!")
}

D:gocode1.14.3gocodegateway_demodemoaseunpack cp_clientmain.go

package main

import (
    "fmt"
    "github.com/e421083458/gateway_demo/demo/base/unpack/unpack"
    "net"
)

func main() {
    //simple tcp server
    //1.監聽端口
    listener, err := net.Listen("tcp", "0.0.0.0:9090")
    if err != nil {
        fmt.Printf("listen fail, err: %v
", err)
        return
    }

    //2.接收請求
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Printf("accept fail, err: %v
", err)
            continue
        }

        //3.創建協程
        go process(conn)
    }
}

func process(conn net.Conn) {
    defer conn.Close()
    for {
        bt, err := unpack.Decode(conn)
        if err != nil {
            fmt.Printf("read from connect failed, err: %v
", err)
            break
        }
        str := string(bt)
        fmt.Printf("receive from client, data: %v
", str)
    }
}

D:gocode1.14.3gocodegateway_demodemoaseunpack cp_servermain.go

golang創建udp服務和客戶端

package main

import (
    "fmt"
    "net"
)

func main() {
    //step 1 連接服務器
    conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
        IP:   net.IPv4(127, 0, 0, 1),
        Port: 9090,
    })

    if err != nil {
        fmt.Printf("connect failed, err: %v
", err)
        return
    }

    for i := 0; i < 100; i++ {
        //step 2 發送數據
        _, err = conn.Write([]byte("hello server!"))
        if err != nil {
            fmt.Printf("send data failed, err : %v
", err)
            return
        }

        //step 3 接收數據
        result := make([]byte, 1024)
        n, remoteAddr, err := conn.ReadFromUDP(result)
        if err != nil {
            fmt.Printf("receive data failed, err: %v
", err)
            return
        }
        fmt.Printf("receive from addr: %v  data: %v
", remoteAddr, string(result[:n]))
    }
}

D:gocode1.14.3gocodegateway_demodemoaseudp_clientmain.go

package main

import (
    "fmt"
    "net"
)

func main() {
    //step 1 監聽服務器
    listen, err := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 9090,
    })
    if err != nil {
        fmt.Printf("listen failed, err:%v
", err)
        return
    }

    //step 2 循環讀取消息內容
    for {
        var data [1024]byte
        n, addr, err := listen.ReadFromUDP(data[:])
        if err != nil {
            fmt.Printf("read failed from addr: %v, err: %v
", addr, err)
            break
        }

        go func() {
            //todo sth
            //step 3 回復數據
            fmt.Printf("addr: %v data: %v  count: %v
", addr, string(data[:n]), n)
            _, err = listen.WriteToUDP([]byte("received success!"), addr)
            if err != nil {
                fmt.Printf("write failed, err: %v
", err)
            }
        }()
    }
}

D:gocode1.14.3gocodegateway_demodemoaseudp_servermain.go

golang創建tcp服務器和客戶端

package main

import (
    "fmt"
    "net"
)

func main() {
    //1、監聽端口
    listener, err := net.Listen("tcp", "0.0.0.0:9090")
    if err != nil {
        fmt.Printf("listen fail, err: %v
", err)
        return
    }

    //2.建立套接字連接
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Printf("accept fail, err: %v
", err)
            continue
        }

        //3. 創建處理協程
        go process(conn)
    }
}

func process(conn net.Conn) {
    defer conn.Close()    //思考題:這里不填寫會有啥問題?
    for {
        var buf [128]byte
        n, err := conn.Read(buf[:])

        if err != nil {
            fmt.Printf("read from connect failed, err: %v
", err)
            break
        }
        str := string(buf[:n])
        fmt.Printf("receive from client, data: %v
", str)
    }
}

服務端

package client

import (
    "bufio"
    "fmt"
    "net"
    "os"
    "strings"
)

func main()  {
    doSend()
    fmt.Print("doSend over")
    doSend()
    fmt.Print("doSend over")
    //select {}
}


func doSend() {
    //1、連接服務器
    conn, err := net.Dial("tcp", "localhost:9090")
    defer conn.Close()    //思考題:這里不填寫會有啥問題?
    if err != nil {
        fmt.Printf("connect failed, err : %v
", err.Error())
        return
    }
    //2、讀取命令行輸入
    inputReader := bufio.NewReader(os.Stdin)
    for {
        // 3、一直讀取直到讀到

        input, err := inputReader.ReadString('
')
        if err != nil {
            fmt.Printf("read from console failed, err: %v
", err)
            break
        }
        // 4、讀取Q時停止
        trimmedInput := strings.TrimSpace(input)
        if trimmedInput == "Q" {
            break
        }
        // 5、回復服務器信息
        _, err = conn.Write([]byte(trimmedInput))
        if err != nil {
            fmt.Printf("write failed , err : %v
", err)
            break
        }
    }
}

客戶端

客戶端:defer conn.Close()  //思考題:這里不填寫會有啥問題?(連接一直在建立狀態,除非tcp連接探測后才會關閉)

服務端:defer conn.Close()  //思考題:這里不填寫會有啥問題?
客戶端發起了關閉,服務端沒有關閉,此時按照四次揮手圖分析:
客戶端是主動關閉方,客戶端此時處于FIN-WAIT-2;
服務端屬于被動關閉方,服務端處于CLOSE-WAIT狀態;

golang創建http服務

服務端:

創建路由器;
設置路由規則;
創建服務器;
監聽端口并提供服務;

客戶端:

創建連接池:
創建客戶端;
請求數據;
讀取內容;

package main

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

func main() {
    // 創建連接池
    transport := &http.Transport{
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second, //連接超時
            KeepAlive: 30 * time.Second, //探活時間
        }).DialContext,
        MaxIdleConns:          100,              //最大空閑連接
        IdleConnTimeout:       90 * time.Second, //空閑超時時間
        TLSHandshakeTimeout:   10 * time.Second, //tls握手超時時間
        ExpectContinueTimeout: 1 * time.Second,  //100-continue狀態碼超時時間
    }
    // 創建客戶端
    client := &http.Client{
        Timeout:   time.Second * 30, //請求超時時間
        Transport: transport,
    }
    // 請求數據
    resp, err := client.Get("http://127.0.0.1:1210/bye")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    // 讀取內容
    bds, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(bds))
}

http客戶端

package main

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

var (
    Addr = ":1210"
)

func main() {
    // 創建路由器
    mux := http.NewServeMux()
    // 設置路由規則
    mux.HandleFunc("/bye", sayBye)
    // 創建服務器
    server := &http.Server{
        Addr:         Addr,
        WriteTimeout: time.Second * 3,
        Handler:      mux,
    }
    // 監聽端口并提供服務
    log.Println("Starting httpserver at "+Addr)
    log.Fatal(server.ListenAndServe())
}

func sayBye(w http.ResponseWriter, r *http.Request) {
    time.Sleep(1 * time.Second)
    w.Write([]byte("bye bye ,this is httpServer"))
}

http服務端

golang http服務器源碼分析:

在分析httpserver源碼之前,請看看此文章 ,了解下type func的用法,函數式一等公民概念,不然下面代碼可能難以理解。

type關鍵字的用法

從最簡單的例子開始:

package main

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

var (
    Addr = ":1210"
)

func main() {
    // 創建路由器
    mux := http.NewServeMux()
    // 設置路由規則
    mux.HandleFunc("/bye", sayBye)
    // 創建服務器
    server := &http.Server{
        Addr:         Addr,
        WriteTimeout: time.Second * 3,
        Handler:      mux,
    }
    // 監聽端口并提供服務
    log.Println("Starting httpserver at "+Addr)
    log.Fatal(server.ListenAndServe())
}

func sayBye(w http.ResponseWriter, r *http.Request) {
    time.Sleep(1 * time.Second)
    w.Write([]byte("bye bye ,this is httpServer"))
}

來看看HandleFunc是啥?

// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}
HandlerFunc(handler)

此處就是用到了type關鍵字 把一個函數轉成HandlerFunc 類型,并且實現了ServeHTTP方法

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

ServeHTTP方法又實現了Handler接口

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

通過回調思路最終執行了sayBye()

mu:一把鎖

m:存放著路由和回調函數

type ServeMux struct {
    mu    sync.RWMutex
    m     map[string]muxEntry
    es    []muxEntry // slice of entries sorted from longest to shortest.
    hosts bool       // whether any patterns contain hostnames
}

h 注冊的函數

pattern 注冊的路由

type muxEntry struct {
    h       Handler
    pattern string
}

注冊路由

mux.Handle(pattern, HandlerFunc(handler))

開啟服務:

func (srv *Server) ListenAndServe() error {
    if srv.shuttingDown() {
        return ErrServerClosed
    }
    addr := srv.Addr
    if addr == "" {
        addr = ":http"
    }
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    return srv.Serve(ln)
}
func (srv *Server) Serve(l net.Listener) error

處理鏈接:

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
    if r.RequestURI == "*" {
        if r.ProtoAtLeast(1, 1) {
            w.Header().Set("Connection", "close")
        }
        w.WriteHeader(StatusBadRequest)
        return
    }
    h, _ := mux.Handler(r)
    h.ServeHTTP(w, r)
}
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)

httpClient源碼簡單解析:

先看看一個簡單的例子:

package main

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

func main() {
    // 創建連接池
    transport := &http.Transport{
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second, //連接超時
            KeepAlive: 30 * time.Second, //探活時間
        }).DialContext,
        MaxIdleConns:          100,              //最大空閑連接
        IdleConnTimeout:       90 * time.Second, //空閑超時時間
        TLSHandshakeTimeout:   10 * time.Second, //tls握手超時時間
        ExpectContinueTimeout: 1 * time.Second,  //100-continue狀態碼超時時間
    }
    // 創建客戶端
    client := &http.Client{
        Timeout:   time.Second * 30, //請求超時時間
        Transport: transport,
    }
    // 請求數據
    resp, err := client.Get("http://127.0.0.1:1210/bye")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    // 讀取內容
    bds, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(bds))
}

分析以后繼續。。。。。。。。

下一篇網絡代理之HTTP代理

總結

以上是生活随笔為你收集整理的golang微服务网关一:网络基础知识扫盲(温故而知新)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 99er热精品视频 | 色综合91| 加勒比波多野结衣 | 日韩中文字幕二区 | 国产成人a人亚洲精品无码 在线aa | 久久久久久久极品 | 欧美国产另类 | 97公开视频| 亚洲精品人妻无码 | 我们好看的2018视频在线观看 | 欧美日韩亚洲系列 | 蜜桃成人在线 | 一本色道久久综合亚洲 | 欧美区日韩区 | www黄色在线观看 | 永久视频在线观看 | 国产精品午夜在线观看 | 欧美日韩一区二区三区国产精品成人 | 夜夜骑夜夜 | 久久久久亚洲av成人网人人软件 | 久草香蕉在线 | 亚洲精品鲁一鲁一区二区三区 | 91精品导航| 91麻豆免费看 | 午夜免费播放观看在线视频 | 香蕉视频污视频 | 中文字幕在线二区 | 久久精品精品 | 丰满岳乱妇国产精品一区 | 久久精品女人 | 成年人免费av | 欧美乱妇15p | 伊人色图 | 激情伊人网 | 蜜桃视频在线观看一区二区 | 亚洲美女视频网 | 久久久毛片 | 欧美片一区二区 | 美女精品在线 | 国产免费专区 | 伊人精品 | 欧美专区日韩专区 | 一级免费a | 18成人在线观看 | 色就是色综合 | 在线观看特色大片免费网站 | 四虎影院永久地址 | 日韩精品一区在线播放 | 国产女教师一区二区三区 | 欧美日在线观看 | 欧美熟妇交换久久久久久分类 | 相亲对象是问题学生动漫免费观看 | 97人妻一区二区精品免费视频 | 欧美精品一区二区三区久久久竹菊 | av免费在线网站 | 色哟哟视频网站 | 人妻 日韩精品 中文字幕 | 午夜啪啪网站 | 天天综合永久 | 黄片毛片视频 | 国精产品一区一区三区有限公司杨 | 日韩毛片免费看 | www视频在线观看 | 初音未来打屁股 | 欧美性久久久久 | 亚洲二区在线播放视频 | 久久国内视频 | 理论片午午伦夜理片影院99 | 国产911| 大肉大捧一进一出好爽视频 | 日操夜操天天操 | 黄视频网站在线 | 熟女俱乐部一区二区视频在线 | 强行挺进白丝老师翘臀网站 | 中国国产黄色片 | www.av欧美 | 精品视频在线一区二区 | 欧美美女在线观看 | 亚洲女人av | 无码精品视频一区二区三区 | 中文字幕一级二级三级 | 欧美jizzhd精品欧美18 | 中国精品毛片 | 丝袜一区二区三区四区 | 又黄又爽又色的视频 | 国产精久久久久久 | 久久.com | 亚洲中文字幕无码av永久 | 男同av在线观看一区二区三区 | 亚洲国产精品成人综合 | 欧洲亚洲综合 | 国产欧美一区二区三区鸳鸯浴 | 黑人精品欧美一区二区蜜桃 | 中文字幕无码不卡免费视频 | 青青草网址 | 在线不卡欧美 | 欧美在线免费 | 天天爽夜夜 | 96看片|