激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Golang - 一篇文章帶你了解Go語言基礎之網絡編程

一篇文章帶你了解Go語言基礎之網絡編程

2020-12-30 22:58Go語言進階學習Go進階者 Golang

本次章節我們講述了什么是TCP,什么是UDP。并且編寫了代碼如何實現TCP服務端,TCP客戶端,UDP服務端,UDP客戶端。講述了為什么會出現粘包,該怎么解決粘包。

一篇文章帶你了解Go語言基礎之網絡編程

前言

Hi,大家好呀,我是碼農,星期八,我們身處21世紀,我們的世界已經在不知不覺中,就像很多網一樣在互聯互通。

互聯網是一個統稱,目前比較常用的有TCP,UDP協議。

當然,還有很多其他的協議,但是本次主要講最常用的TCP和UDP協議。

socker編程

我們所學的TCP和UDP,統稱為Socker編程,也叫做套接字編程。

多臺機器要實現互相通訊,其實是一個非常復雜的過程,底層從鋪設網線,網線接口,交換機,路由器,在到規定各種協議。

再到應用層QQ,微信等軟件。

如果沒有一套標準,每次使用都要自己去實現,可能每個程序員都不是掉頭發那么簡單了!

有了Socker之后,Socker會在應用層之前,將各種繁瑣的的底層操作隱藏,我們可能只需要Socker.TCP就實現了TCP協議的通訊。

Go語言TCP

TCP屬于穩定的,可靠的長連接,

既然要涉及通訊,必然有兩個終端,最起碼一個是服務端,一個是客戶端,就像我們的淘寶,我們每次打開淘寶,都要去鏈接它,當然,淘寶可不直接是TCP。

服務端

在Go中實現服務端,并且在服務端并發很簡單,只需要將每個連接讓一個協程處理即可!

代碼

package main 

 

import ( 

    "bufio" 

    "fmt" 

    "net" 

 

func process(conn net.Conn) { 

    defer conn.Close() 

    for { 

        reader := bufio.NewReader(conn) 

        buf := make([]byte, 128) 

        n, err := reader.Read(buf) 

        if err != nil { 

            fmt.Println("數據讀取失敗", err) 

            return 

        } 

        recvStr := string(buf[:n]) 

        fmt.Println("客戶端發送過來的值:", recvStr) 

 

func main() { 

    lister, err := net.Listen("tcp", "0.0.0.0:8008"

    if err != nil { 

        fmt.Println("連接失敗", err) 

    for { 

        fmt.Println("等待建立連接,此時會阻塞住"

        conn, err := lister.Accept() //等待建立連接 

        fmt.Println("連接建立成功,繼續"

        if err != nil { 

            fmt.Println("建立連接失敗", err) 

            //繼續監聽下次鏈接 

            continue 

        } 

        go process(conn) 

客戶端

客戶端就很簡單了,相對來說是不需要并發的,只需要連接就行。

代碼

package main 

 

import ( 

    "bufio" 

    "fmt" 

    "net" 

    "os" 

 

//客戶端 

func main() { 

    conn, err := net.Dial("tcp", "192.168.10.148:8008"

    if err != nil { 

        fmt.Println("連接服務器失敗",err) 

    defer conn.Close() 

    inputReader:=bufio.NewReader(os.Stdin) 

    for

        fmt.Println(":"

        input,_:=inputReader.ReadString('\n'

        _, err = conn.Write([]byte(input)) 

        if err != nil { 

            fmt.Println("發送成功"

        } 

執行結果

就這樣,我們實現了服務端并發的處理所有客戶端的請求。

一篇文章帶你了解Go語言基礎之網絡編程

粘包

我們先看一下什么是粘包。

服務端

package main 

 

import ( 

    "bufio" 

    "fmt" 

    "io" 

    "net" 

 

func process(conn net.Conn) { 

    defer conn.Close() 

    reader := bufio.NewReader(conn) 

    buf := make([]byte, 1024) 

    for { 

        n, err := reader.Read(buf) 

        //讀完了 

        if err == io.EOF { 

            fmt.Println("讀完了"

            break 

        } 

        //讀錯了 

        if err != nil { 

            fmt.Println("數據讀取失敗", err) 

            return 

        } 

        recvStr := string(buf[:n]) 

        fmt.Println("客戶端發送過來的值:", recvStr) 

 

func main() { 

    lister, err := net.Listen("tcp", "0.0.0.0:8008"

    if err != nil { 

        fmt.Println("連接失敗", err) 

        return 

    defer lister.Close() 

    for { 

        fmt.Println("等待建立連接,此時會阻塞住"

        conn, err := lister.Accept() //等待建立連接 

        fmt.Println("連接建立成功,繼續"

        if err != nil { 

            fmt.Println("建立連接失敗", err) 

            //繼續監聽下次鏈接 

            continue 

        } 

        go process(conn) 

客戶端

package main 

 

import ( 

    "fmt" 

    "net" 

 

//客戶端 

func main() { 

    conn, err := net.Dial("tcp", "192.168.10.148:8008"

    if err != nil { 

        fmt.Println("連接服務器失敗", err) 

    defer conn.Close() 

    for i := 0; i < 10; i++ { 

        sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads " 

        conn.Write([]byte(sendStr)) 

        time.Sleep(time.Second

注意:18行代碼睡眠了1s

執行結果

一篇文章帶你了解Go語言基礎之網絡編程

如果我注釋了第18行代碼

一篇文章帶你了解Go語言基礎之網絡編程

執行結果

一篇文章帶你了解Go語言基礎之網絡編程

直接都淦到一行了,what?這是啥情況,不應該跟原來一樣嗎???

每發送一個值,那邊就接收一下,這怎么整到一塊了!!!

原因

主要原因是因為我們是應用層軟件,是跑在操作系統之上的軟件,當我們向服務器發送一個數據時,是調用操作系統的相關接口發送的,操作系統再經過各種復雜的操作,發送到對方機器

但是操作系統有一個發送數據緩沖區,默認情況如果緩沖區是有大小的,如果緩沖區沒滿,是不會發送數據的,所以上述客戶端在發送數據時,系統的緩沖區都沒滿,一直壓在了操作系統的緩沖區中,最后發現沒數據了,才一次都發送到服務端

但是為什么sleep(1)又管用了呢?這是因為緩沖區不止一個程序在用,1s的時間足夠其他程序將緩沖區打滿,然后各自發各自的數據,這也是為什么第一次操作沒問題,第二次有問題,因為第二次全部都是我們客戶端打滿的

一篇文章帶你了解Go語言基礎之網絡編程

解決粘包

工具函數

我們將解包封包的函數封裝一下

socker_sitck/stick.go 

 一篇文章帶你了解Go語言基礎之網絡編程

package socker_stick 

 

import ( 

    "bufio" 

    "bytes" 

    "encoding/binary" 

    "fmt" 

 

//Encode 將消息編碼 

func Encode(message string) ([]byte, error) { 

    length := int32(len(message)) 

    var pkg = new(bytes.Buffer) 

    //寫入消息頭 

    err := binary.Write(pkg, binary.LittleEndian, length) 

    if err != nil { 

        fmt.Println("寫入消息頭失敗", err) 

        return nil, err 

    //寫入消息實體 

    err = binary.Write(pkg, binary.LittleEndian, []byte(message)) 

    if err != nil { 

        fmt.Println("寫入消息實體失敗", err) 

        return nil, err 

    return pkg.Bytes(), nil 

 

//Decode解碼消息 

func Decode(reader *bufio.Reader) (string, error) { 

    //讀取信息長度 

    lengthByte, _ := reader.Peek(4) 

    lengthBuff := bytes.NewBuffer(lengthByte) 

    var length int32 

    err := binary.Read(lengthBuff, binary.LittleEndian, &length) 

    if err != nil { 

        return "", err 

    //BuffRead 返回緩沖區現有的可讀的字節數 

    if int32(reader.Buffered()) < length+4 { 

        return "", err 

    pack := make([]byte, int(4+length)) 

    _, err = reader.Read(pack) 

    if err != nil { 

        return "", err 

    return string(pack[4:]), nil 

服務端

package main 

 

import ( 

    "a3_course/socker_stick" 

    "bufio" 

    "fmt" 

    "io" 

    "net" 

 

func process(conn net.Conn) { 

    defer conn.Close() 

    reader := bufio.NewReader(conn) 

 

    for { 

        msg, err := socker_stick.Decode(reader) 

        //讀完了 

        if err == io.EOF { 

            fmt.Println("讀完了"

            break 

        } 

        //讀錯了 

        if err != nil { 

            fmt.Println("數據讀取失敗", err) 

            return 

        } 

 

        fmt.Println("客戶端發送過來的值:", msg) 

 

func main() { 

    lister, err := net.Listen("tcp", "0.0.0.0:8008"

    if err != nil { 

        fmt.Println("連接失敗", err) 

        return 

    defer lister.Close() 

    for { 

        fmt.Println("等待建立連接,此時會阻塞住"

        conn, err := lister.Accept() //等待建立連接 

        fmt.Println("連接建立成功,繼續"

        if err != nil { 

            fmt.Println("建立連接失敗", err) 

            //繼續監聽下次鏈接 

            continue 

        } 

        go process(conn) 

客戶端

package main 

 

import ( 

    "a3_course/socker_stick" 

    "fmt" 

    "net" 

 

//客戶端 

func main() { 

    conn, err := net.Dial("tcp", "192.168.10.148:8008"

    if err != nil { 

        fmt.Println("連接服務器失敗", err) 

    defer conn.Close() 

    for i := 0; i < 10; i++ { 

        sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads " 

        data, err := socker_stick.Encode(sendStr) 

        if err != nil { 

            fmt.Println("編碼失敗",err) 

            return 

        } 

        conn.Write(data) 

        //time.Sleep(time.Second

執行結果

一篇文章帶你了解Go語言基礎之網絡編程

這次真的不管執行幾次,都是這樣的結果

對了,只有TCP才有粘包

Go語言UDP

UDP是一個無連接協議,客戶端不會在乎服務端有沒有問題,客戶端只管發,通常用于實時性比較高的領域

例如直播行業

服務端

package main 

 

import ( 

    "fmt" 

    "net" 

 

func main() { 

    listen, err := net.ListenUDP("udp", &net.UDPAddr{ 

        IP:   net.IPv4(0, 0, 0, 0), 

        Port: 8009, 

}) 

    if err != nil { 

        panic(fmt.Sprintf("udp啟動失敗,err:%v", err)) 

    defer listen.Close() 

    for

        var data = make([]byte,1024) 

        n, addr, err := listen.ReadFromUDP(data) 

        if err != nil { 

            panic(fmt.Sprintf("讀取數據失敗,err:%v", err)) 

        } 

        fmt.Println(string(data[:n]),addr,n) 

客戶端

package main 

 

import ( 

    "fmt" 

    "net" 

 

func main() { 

    socker, err := net.DialUDP("udp", nil, &net.UDPAddr{ 

        IP:   net.IPv4(0, 0, 0, 0), 

        Port: 8009, 

}) 

    if err != nil { 

        panic(fmt.Sprintf("連接服務器失敗,err:%v", err)) 

    defer socker.Close() 

    sendStr:="你好呀" 

    _, err = socker.Write([]byte(sendStr)) 

    if err != nil { 

        panic(fmt.Sprintf("數據發送失敗,err:%v", err)) 

執行結果

一篇文章帶你了解Go語言基礎之網絡編程

總結

本次章節我們講述了什么是TCP,什么是UDP。

并且編寫了代碼如何實現TCP服務端,TCP客戶端,UDP服務端,UDP客戶端。

講述了為什么會出現粘包,該怎么解決粘包。

逆水行舟,不進則退!

原文地址:https://mp.weixin.qq.com/s/vBk1wF9uDZKIjhxfFRAgtw

延伸 · 閱讀

精彩推薦
  • Golanggolang的httpserver優雅重啟方法詳解

    golang的httpserver優雅重啟方法詳解

    這篇文章主要給大家介紹了關于golang的httpserver優雅重啟的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    helight2992020-05-14
  • Golanggolang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網11352020-05-21
  • Golanggolang json.Marshal 特殊html字符被轉義的解決方法

    golang json.Marshal 特殊html字符被轉義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • GolangGolang中Bit數組的實現方式

    Golang中Bit數組的實現方式

    這篇文章主要介紹了Golang中Bit數組的實現方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • GolangGolang通脈之數據類型詳情

    Golang通脈之數據類型詳情

    這篇文章主要介紹了Golang通脈之數據類型,在編程語言中標識符就是定義的具有某種意義的詞,比如變量名、常量名、函數名等等,Go語言中標識符允許由...

    4272021-11-24
  • Golanggo日志系統logrus顯示文件和行號的操作

    go日志系統logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
主站蜘蛛池模板: 看全色黄大色黄大片女图片 | 国产美女视频一区二区三区 | 成人在线视频播放 | 亚洲国产超高清a毛毛片 | 亚洲一级片在线观看 | 媚药按摩痉挛w中文字幕 | 日韩视频在线一区二区三区 | 日韩视频―中文字幕 | 日本在线免费观看视频 | 日韩av电影免费看 | 国产午夜精品一区二区三区嫩草 | 国产在线观看91精品 | 国产88久久久国产精品免费二区 | 高清国产午夜精品久久久久久 | 激情大乳女做爰办公室韩国 | 97中文| 999精品久久久 | 91av在线免费播放 | 最近中文字幕一区二区 | 久久草在线视频 | 久久国产精品99久久人人澡 | 久久精品毛片 | 爱高潮www亚洲精品 国产一区二区三区视频免费 | 青久草视频 | 中文字幕在线观看电影 | 久草在线资源福利站 | 欧美一a一片一级一片 | 免费人成年短视频在线观看网站 | 九九热视频免费观看 | 成人福利在线免费观看 | 国产精品久久久久久久久久大牛 | 欧日韩在线视频 | 欧美一级理论 | 国产亚洲欧美日韩在线观看不卡 | 国产亚洲精品久久久久5区 日韩一级片一区二区三区 国产精品久久久久av | 中文黄色一级片 | 精国产品一区二区三区四季综 | 国产免费一区视频 | 伊人欧美 | 久久精品国产一区二区电影 | xxxxxx视频 |