亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

Go語言基于Socket編寫服務器端與客戶端通信的實例

2020-04-01 19:12:08
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了Go語言基于Socket編寫服務器端與客戶端通信的實例,包括實現基于自定義通訊協議的Socket通信,需要的朋友可以參考下
 

在golang中,網絡協議已經被封裝的非常完好了,想要寫一個Socket的Server,我們并不用像其他語言那樣需要為socket、bind、listen、receive等一系列操作頭疼,只要使用Golang中自帶的net包即可很方便的完成連接等操作~
在這里,給出一個最最基礎的基于Socket的Server的寫法:

復制代碼代碼如下:

package main  
import (  
    "fmt"  
    "net"  
    "log"  
    "os"  
)  
  
  
func main() {  
  
//建立socket,監聽端口  
    netListen, err := net.Listen("tcp", "localhost:1024")  
    CheckError(err)  
    defer netListen.Close()  
  
    Log("Waiting for clients")  
    for {  
        conn, err := netListen.Accept()  
        if err != nil {  
            continue  
        }  
  
        Log(conn.RemoteAddr().String(), " tcp connect success")  
        handleConnection(conn)  
    }  
}  
//處理連接  
func handleConnection(conn net.Conn) {  
  
    buffer := make([]byte, 2048)  
  
    for {  
  
        n, err := conn.Read(buffer)  
  
        if err != nil {  
            Log(conn.RemoteAddr().String(), " connection error: ", err)  
            return  
        }  
  
  
        Log(conn.RemoteAddr().String(), "receive data string:/n", string(buffer[:n]))  
  
    }  
  
}  
func Log(v ...interface{}) {  
    log.Println(v...)  
}  
  
func CheckError(err error) {  
    if err != nil {  
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())  
        os.Exit(1)  
    }  
}  

 

唔,拋除Go語言里面10行代碼有5行error的蛋疼之處,你可以看到,Server想要建立并接受一個Socket,其核心流程就是

復制代碼代碼如下:

netListen, err := net.Listen("tcp", "localhost:1024") 

 

conn, err := netListen.Accept() 

n, err := conn.Read(buffer)  


這三步,通過Listen、Accept 和Read,我們就成功的綁定了一個端口,并能夠讀取從該端口傳來的內容~
Server寫好之后,接下來就是Client方面啦,我手寫一個HelloWorld給大家:
復制代碼代碼如下:

package main  
  
import (  
    "fmt"  
    "net"  
    "os"  
)  
  
func sender(conn net.Conn) {  
        words := "hello world!"  
        conn.Write([]byte(words))  
    fmt.Println("send over")  
  
}  
  
  
  
func main() {  
    server := "127.0.0.1:1024"  
    tcpAddr, err := net.ResolveTCPAddr("tcp4", server)  
    if err != nil {  
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())  
        os.Exit(1)  
    }  
  
    conn, err := net.DialTCP("tcp", nil, tcpAddr)  
    if err != nil {  
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())  
        os.Exit(1)  
    }  
  
  
    fmt.Println("connect success")  
    sender(conn)  
  
}  

可以看到,Client這里的關鍵在于
復制代碼代碼如下:

tcpAddr, err := net.ResolveTCPAddr("tcp4", server) 

 

conn, err := net.DialTCP("tcp", nil, tcpAddr)  


這兩步,主要是負責解析端口和連接~
寫好Server和Client之后,讓我們運行一下看看:~~
成功運行,Console出現Server等待連接的提示:

 

Go語言,Socket

Go語言,Socket

Go語言,Socket

Server端成功的收到了我們的Hello-World啦,至于后面的那行紅字,則是斷開連接的提示~

到這里,一個最基礎的使用Socket的Server-Client框架就出來啦~
如果想要讓Server能夠響應來自不同Client的請求,我們只要在Server端的代碼的main入口中,
在 handleConnection(conn net.Conn) 這句代碼的前面加上一個 go,就可以讓服務器并發處理不同的Client發來的請求啦

自定義通訊協議
在上面我們做出來一個最基礎的demo后,已經可以初步實現Server和Client之間的信息交流了~ 這一章我會介紹一下怎么在Server和Client之間實現一個簡單的通訊協議,從而增強整個信息交流過程的穩定性。
        在Server和client的交互過程中,有時候很難避免出現網絡波動,而在通訊質量較差的時候,Client有可能無法將信息流一次性完整發送,最終傳到Server上的信息很可能變為很多段。
        如下圖所示,本來應該是分條傳輸的json,結果因為一些原因連接在了一起,這時候就會出現問題啦,Server端要怎么判斷收到的消息是否完整呢?~

Go語言,Socket

 唔,答案就是這篇文章的主題啦:在Server和Client交互的時候,加入一個通訊協議(protocol),讓二者的交互通過這個協議進行封裝,從而使Server能夠判斷收到的信息是否為完整的一段。(也就是解決分包的問題)
        因為主要目的是為了讓Server能判斷客戶端發來的信息是否完整,因此整個協議的核心思路并不是很復雜:
協議的核心就是設計一個頭部(headers),在Client每次發送信息的時候將header封裝進去,再讓Server在每次收到信息的時候按照預定格式將消息進行解析,這樣根據Client傳來的數據中是否包含headers,就可以很輕松的判斷收到的信息是否完整了~
        如果信息完整,那么就將該信息發送給下一個邏輯進行處理,如果信息不完整(缺少headers),那么Server就會把這條信息與前一條信息合并繼續處理。

        下面是協議部分的代碼,主要分為數據的封裝(Enpack)和解析(Depack)兩個部分,其中Enpack用于Client端將傳給服務器的數據封裝,而Depack是Server用來解析數據,其中Const部分用于定義Headers,HeaderLength則是Headers的長度,用于后面Server端的解析。這里要說一下ConstMLength,這里代表Client傳入信息的長度,因為在golang中,int轉為byte后會占4長度的空間,因此設定為4。每次Client向Server發送信息的時候,除了將Headers封裝進去意以外,還會將傳入信息的長度也封裝進去,這樣可以方便Server進行解析和校驗。

復制代碼代碼如下:

//通訊協議處理  
package protocol  
  
import (  
    "bytes"  
    "encoding/binary"  
)  
const (  
    ConstHeader         = "Headers"  
    ConstHeaderLength   = 7  
    ConstMLength = 4  
)  
  
//封包  
func Enpack(message []byte) []byte {  
    return append(append([]byte(ConstHeader), IntToBytes(len(message))...), message...)  
}  
  
//解包  
func Depack(buffer []byte, readerChannel chan []byte) []byte {  
    length := len(buffer)  
  
    var i int  
    for i = 0; i < length; i = i + 1 {  
        if length < i+ConstHeaderLength+ConstMLength {  
            break  
        }  
        if string(buffer[i:i+ConstHeaderLength]) == ConstHeader {  
            messageLength := BytesToInt(buffer[i+ConstHeaderLength : i+ConstHeaderLength+ConstMLength])  
            if length < i+ConstHeaderLength+ConstLength+messageLength {  
                break  
            }  
            data := buffer[i+ConstHeaderLength+ConstMLength : i+ConstHeaderLength+ConstMLength+messageLength]  
            readerChannel <- data  
  
        }  
    }  
  
    if i == length {  
        return make([]byte, 0)  
    }  
    return buffer[i:]  
}  
  
//整形轉換成字節  
func IntToBytes(n int) []byte {  
    x := int32(n)  
  
    bytesBuffer := bytes.NewBuffer([]byte{})  
    binary.Write(bytesBuffer, binary.BigEndian, x)  
    return bytesBuffer.Bytes()  
}  
  
//字節轉換成整形  
func BytesToInt(b []byte) int {  
    bytesBuffer := bytes.NewBuffer(b)  
  
    var x int32  
    binary.Read(bytesBuffer, binary.BigEndian, &x)  
  
    return int(x)  
}  

        協議寫好之后,接下來就是在Server和Client的代碼中應用協議啦,下面是Server端的代碼,主要負責解析Client通過協議發來的信息流:
復制代碼代碼如下:

package main    
    
import (    
    "protocol"    
    "fmt"    
    "net"    
    "os"    
)    
    
func main() {    
    netListen, err := net.Listen("tcp", "localhost:6060")    
    CheckError(err)    
    
    defer netListen.Close()    
    
    Log("Waiting for clients")    
    for {    
        conn, err := netListen.Accept()    
        if err != nil {    
            continue    
        }    
    
        //timeouSec :=10    
        //conn.    
        Log(conn.RemoteAddr().String(), " tcp connect success")    
        go handleConnection(conn)    
    
    }    
}    
    
func handleConnection(conn net.Conn) {    
    
    
    // 緩沖區,存儲被截斷的數據    
    tmpBuffer := make([]byte, 0)    
    
    //接收解包    
    readerChannel := make(chan []byte, 16)    
    go reader(readerChannel)    
    
    buffer := make([]byte, 1024)    
    for {    
    n, err := conn.Read(buffer)    
    if err != nil {    
    Log(conn.RemoteAddr().String(), " connection error: ", err)    
    return    
    }    
    
    tmpBuffer = protocol.Depack(append(tmpBuffer, buffer[:n]...), readerChannel)    
    }    
    defer conn.Close()    
}    
    
func reader(readerChannel chan []byte) {    
    for {    
        select {    
        case data := <-readerChannel:    
            Log(string(data))    
        }    
    }    
}    
    
func Log(v ...interface{}) {    
    fmt.Println(v...)    
}    
    
func CheckError(err error) {    
    if err != nil {    
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())    
        os.Exit(1)    
    }    
}    

 

        然后是Client端的代碼,這個簡單多了,只要給信息封裝一下就可以了~:

復制代碼代碼如下:

package main    
import (    
"protocol"    
"fmt"    
"net"    
"os"    
"time"    
"strconv"    
    
)    
    
func send(conn net.Conn) {    
    for i := 0; i < 100; i++ {    
        session:=GetSession()    
        words := "{/"ID/":"+ strconv.Itoa(i) +"/",/"Session/":"+session +"2015073109532345/",/"Meta/":/"golang/",/"Content/":/"message/"}"    
        conn.Write(protocol.Enpacket([]byte(words)))    
    }    
    fmt.Println("send over")    
    defer conn.Close()    
}    
    
func GetSession() string{    
    gs1:=time.Now().Unix()    
    gs2:=strconv.FormatInt(gs1,10)    
    return gs2    
}    
    
func main() {    
    server := "localhost:6060"    
    tcpAddr, err := net.ResolveTCPAddr("tcp4", server)    
    if err != nil {    
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())    
        os.Exit(1)    
    }    
    
    conn, err := net.DialTCP("tcp", nil, tcpAddr)    
    if err != nil {    
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())    
        os.Exit(1)    
    }    
    
    
    fmt.Println("connect success")    
    send(conn)    
    
    
    
}    

這樣我們就成功實現在Server和Client之間建立一套自定義的基礎通訊協議啦,讓我們運行一下看下效果:

 

Go語言,Socket

成功識別每一條Client發來的信息啦~~


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美日韩精品久久亚洲区| 中国日韩欧美久久久久久久久| 久久影院免费观看| 成人观看高清在线观看免费| 日韩一中文字幕| 亚洲欧美日韩一区二区三区在线| 97婷婷大伊香蕉精品视频| 亚洲精品999| 日韩欧美国产骚| 欧美大尺度电影在线观看| 原创国产精品91| 久久av红桃一区二区小说| 亚洲激情在线观看| 日韩成人性视频| 97成人精品区在线播放| 国产精品成久久久久三级| 日韩黄色av网站| 日韩精品免费综合视频在线播放| 日韩最新免费不卡| 亚洲人成欧美中文字幕| 欧美久久久精品| 久久艳片www.17c.com| 国产欧美日韩中文| 国产精品中文久久久久久久| 2019中文字幕全在线观看| 精品久久中文字幕久久av| 久久免费视频在线观看| 92福利视频午夜1000合集在线观看| 亚洲一区二区黄| 久久天堂av综合合色| 国产精品69久久久久| 超碰91人人草人人干| 亚洲国产福利在线| 98午夜经典影视| 69av在线播放| 国内精品久久久久久| 精品福利一区二区| 色婷婷综合久久久久| 亚洲国产成人精品女人久久久| 欧美巨乳在线观看| 欧美第一黄色网| 亚洲人成网站色ww在线| 欧美激情一区二区三区高清视频| 国产精品av电影| 国产69精品久久久久9999| 国产日韩欧美中文在线播放| 91精品国产色综合久久不卡98| 亚洲第一中文字幕在线观看| 日本精品视频在线观看| www.欧美精品| 免费91麻豆精品国产自产在线观看| 亚洲综合中文字幕在线| 日韩有码片在线观看| 亚洲欧美日韩精品久久| 国产日韩精品在线播放| 亚洲国产小视频在线观看| 视频在线一区二区| 77777亚洲午夜久久多人| 国产精品777| 亚洲成人黄色在线| 日韩成人久久久| 亚洲国产精品嫩草影院久久| 精品国产欧美成人夜夜嗨| 亚洲aⅴ男人的天堂在线观看| 91色在线观看| 久久免费精品日本久久中文字幕| 在线观看日韩专区| 亚洲国产精彩中文乱码av在线播放| 国产日韩欧美另类| 色午夜这里只有精品| 欧美福利在线观看| 日本欧美精品在线| 亚洲午夜久久久久久久| 久久精品国产精品亚洲| 成人免费在线视频网址| 中文字幕亚洲综合久久| 欧美精品制服第一页| 国产精品91在线观看| 18一19gay欧美视频网站| 日韩精品中文字幕在线播放| 久久精品国产欧美亚洲人人爽| 岛国视频午夜一区免费在线观看| 精品久久久久久中文字幕| 欧美精品一二区| 日韩免费观看av| 成人性生交xxxxx网站| 午夜精品久久久久久久99热| 久久久久中文字幕2018| 亚洲精品中文字幕av| 国产日韩在线看| 日韩综合视频在线观看| 国产91在线播放精品91| 美日韩精品免费观看视频| 国产成人欧美在线观看| 精品无码久久久久久国产| 国产精品你懂得| 国产ts一区二区| 亚洲最大福利视频网| 日韩经典一区二区三区| 久久综合五月天| 欧美老妇交乱视频| 欧美激情一区二区久久久| 精品无人区太爽高潮在线播放| 久久久av一区| 欧美激情日韩图片| 亚洲男人天堂2023| 亚洲精品欧美极品| 欧美极品xxxx| 欧美高清不卡在线| 久久久亚洲影院你懂的| 在线成人中文字幕| 大荫蒂欧美视频另类xxxx| 国产精品高潮呻吟视频| 在线国产精品视频| 日韩在线观看你懂的| 中文字幕视频一区二区在线有码| 亚洲国产成人在线视频| 久久久久久com| 久久久国产成人精品| 国产精品视频久久| 欧美日韩国产精品一区二区三区四区| 午夜精品久久久久久99热| 国产日韩av在线播放| 久久久久久中文| 亚洲欧美日韩精品久久| 麻豆国产精品va在线观看不卡| 色综合天天狠天天透天天伊人| 中文字幕亚洲欧美在线| 国产视频精品免费播放| 国产精品女人久久久久久| 久国内精品在线| 久久99国产综合精品女同| 97精品久久久中文字幕免费| 亚洲黄色av网站| 国产91热爆ts人妖在线| 日韩一区二区久久久| 日韩成人网免费视频| 国产在线观看不卡| 日本一欧美一欧美一亚洲视频| 久久久精品国产亚洲| 一区二区三区高清国产| 中文字幕欧美日韩va免费视频| 亚洲国产高潮在线观看| 在线视频中文亚洲| 欲色天天网综合久久| 精品呦交小u女在线| 国产丝袜一区二区三区| 国外视频精品毛片| 亚洲第一色中文字幕| 国产精品旅馆在线| 日本午夜人人精品| 国产91精品在线播放| 色偷偷偷综合中文字幕;dd| 91久久久久久久一区二区| 久久久久久久激情视频| 91天堂在线观看| 成人综合国产精品| 性欧美长视频免费观看不卡| 中文字幕一区二区精品| 97在线视频免费观看| 日韩欧美在线观看视频| 精品国产成人在线| 成人性教育视频在线观看| 国产精品高潮呻吟久久av无限|