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

首頁 > 編程 > Golang > 正文

Go語言基于Socket編寫服務(wù)器端與客戶端通信的實(shí)例

2020-04-01 19:12:08
字體:
供稿:網(wǎng)友
這篇文章主要介紹了Go語言基于Socket編寫服務(wù)器端與客戶端通信的實(shí)例,包括實(shí)現(xiàn)基于自定義通訊協(xié)議的Socket通信,需要的朋友可以參考下
 

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

復(fù)制代碼代碼如下:

package main  
import (  
    "fmt"  
    "net"  
    "log"  
    "os"  
)  
  
  
func main() {  
  
//建立socket,監(jiān)聽端口  
    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想要建立并接受一個(gè)Socket,其核心流程就是

復(fù)制代碼代碼如下:

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

 

conn, err := netListen.Accept() 

n, err := conn.Read(buffer)  


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

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這里的關(guān)鍵在于
復(fù)制代碼代碼如下:

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

 

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


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

 

Go語言,Socket

Go語言,Socket

Go語言,Socket

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

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

自定義通訊協(xié)議
在上面我們做出來一個(gè)最基礎(chǔ)的demo后,已經(jīng)可以初步實(shí)現(xiàn)Server和Client之間的信息交流了~ 這一章我會(huì)介紹一下怎么在Server和Client之間實(shí)現(xiàn)一個(gè)簡單的通訊協(xié)議,從而增強(qiáng)整個(gè)信息交流過程的穩(wěn)定性。
        在Server和client的交互過程中,有時(shí)候很難避免出現(xiàn)網(wǎng)絡(luò)波動(dòng),而在通訊質(zhì)量較差的時(shí)候,Client有可能無法將信息流一次性完整發(fā)送,最終傳到Server上的信息很可能變?yōu)楹芏喽巍?br />         如下圖所示,本來應(yīng)該是分條傳輸?shù)膉son,結(jié)果因?yàn)橐恍┰蜻B接在了一起,這時(shí)候就會(huì)出現(xiàn)問題啦,Server端要怎么判斷收到的消息是否完整呢?~

Go語言,Socket

 唔,答案就是這篇文章的主題啦:在Server和Client交互的時(shí)候,加入一個(gè)通訊協(xié)議(protocol),讓二者的交互通過這個(gè)協(xié)議進(jìn)行封裝,從而使Server能夠判斷收到的信息是否為完整的一段。(也就是解決分包的問題)
        因?yàn)橹饕康氖菫榱俗孲erver能判斷客戶端發(fā)來的信息是否完整,因此整個(gè)協(xié)議的核心思路并不是很復(fù)雜:
協(xié)議的核心就是設(shè)計(jì)一個(gè)頭部(headers),在Client每次發(fā)送信息的時(shí)候?qū)eader封裝進(jìn)去,再讓Server在每次收到信息的時(shí)候按照預(yù)定格式將消息進(jìn)行解析,這樣根據(jù)Client傳來的數(shù)據(jù)中是否包含headers,就可以很輕松的判斷收到的信息是否完整了~
        如果信息完整,那么就將該信息發(fā)送給下一個(gè)邏輯進(jìn)行處理,如果信息不完整(缺少headers),那么Server就會(huì)把這條信息與前一條信息合并繼續(xù)處理。

        下面是協(xié)議部分的代碼,主要分為數(shù)據(jù)的封裝(Enpack)和解析(Depack)兩個(gè)部分,其中Enpack用于Client端將傳給服務(wù)器的數(shù)據(jù)封裝,而Depack是Server用來解析數(shù)據(jù),其中Const部分用于定義Headers,HeaderLength則是Headers的長度,用于后面Server端的解析。這里要說一下ConstMLength,這里代表Client傳入信息的長度,因?yàn)樵趃olang中,int轉(zhuǎn)為byte后會(huì)占4長度的空間,因此設(shè)定為4。每次Client向Server發(fā)送信息的時(shí)候,除了將Headers封裝進(jìn)去意以外,還會(huì)將傳入信息的長度也封裝進(jìn)去,這樣可以方便Server進(jìn)行解析和校驗(yàn)。

復(fù)制代碼代碼如下:

//通訊協(xié)議處理  
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:]  
}  
  
//整形轉(zhuǎn)換成字節(jié)  
func IntToBytes(n int) []byte {  
    x := int32(n)  
  
    bytesBuffer := bytes.NewBuffer([]byte{})  
    binary.Write(bytesBuffer, binary.BigEndian, x)  
    return bytesBuffer.Bytes()  
}  
  
//字節(jié)轉(zhuǎn)換成整形  
func BytesToInt(b []byte) int {  
    bytesBuffer := bytes.NewBuffer(b)  
  
    var x int32  
    binary.Read(bytesBuffer, binary.BigEndian, &x)  
  
    return int(x)  
}  

        協(xié)議寫好之后,接下來就是在Server和Client的代碼中應(yīng)用協(xié)議啦,下面是Server端的代碼,主要負(fù)責(zé)解析Client通過協(xié)議發(fā)來的信息流:
復(fù)制代碼代碼如下:

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) {    
    
    
    // 緩沖區(qū),存儲(chǔ)被截?cái)嗟臄?shù)據(jù)    
    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端的代碼,這個(gè)簡單多了,只要給信息封裝一下就可以了~:

復(fù)制代碼代碼如下:

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)    
    
    
    
}    

這樣我們就成功實(shí)現(xiàn)在Server和Client之間建立一套自定義的基礎(chǔ)通訊協(xié)議啦,讓我們運(yùn)行一下看下效果:

 

Go語言,Socket

成功識別每一條Client發(fā)來的信息啦~~


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
精品视频一区 二区 三区| 日韩和欧美的一区二区| videos性欧美另类高清| 污视频在线看| 人人狠狠综合久久亚洲婷婷| 亚洲视频 中文字幕| 亚洲综合自拍| 欧美日韩视频在线一区二区观看视频| 欧美日韩一区二区不卡| 极品尤物av丝袜美腿在线观看| 欧美被狂躁喷白浆精品| 天堂网www在线中文天堂| 国产精品一区二区久久精品爱涩| 国产www视频在线观看| 国产成人精品自拍| 色一区二区三区| 亚洲色图38p| 91青娱乐在线视频| 四虎精品在永久在线观看| 国产精品美女在线| 天天色综合天天| 四虎884aa成人精品| 日韩一级免费一区| 久久久久亚洲无码| 亚洲丝袜在线视频| 爱豆国产剧免费观看大全剧苏畅| 国产精品亚洲不卡a| 91p九色成人| 久久国产精品二区| 日韩中文视频| 亚洲精品网站在线观看| 国内自拍一区| blacked蜜桃精品一区| 玖草视频在线观看| 亚洲精品网站在线播放gif| 日韩精品一区二区三区外面| av蜜臀在线| 最新91在线视频| 日韩第一页在线观看| 国产精品一区二区男女羞羞无遮挡| 人人精品人人爱| 最新超碰在线| 亚洲欧美精品一区二区三区| 久久国产精品偷| 日日噜噜噜噜久久久精品毛片| 日韩毛片在线播放| 国产肉丝袜一区二区| 狼人综合视频| 国产黄色网址在线观看| 蜜桃av噜噜一区二区三| 日韩不卡av在线| 欧美日韩精品在线一区| 国产一区二区| 福利视频一二区| 性生交大片免费看l| 久久精品人人做人人爽| 欧美视频中文在线看| 日本一区二区三区四区五区| 91蜜桃视频在线| 精品偷拍一区二区三区在线看| 久久日一线二线三线suv| 一区二区三区四区在线视频| 国产精品日韩欧美一区二区| 日韩亚洲欧美在线观看| 欧美精品情趣视频| 国产又黄又嫩又滑又白| 久久久久高清| 久久精品亚洲7777影院| 亚洲精品国产美女| 久久亚洲精品中文字幕冲田杏梨| 影音先锋男人资源在线观看| 成人性生交大片免费网站| 欧美亚洲高清| 3d玉蒲团在线观看| 激情黄色小视频| 毛片在线播放网址| 十八禁视频网站在线观看| 欧美日韩在线播放三区四区| 精品素人av| 国产一区二区三区影院| 久久久国产午夜精品| 午夜在线播放视频欧美| 欧美男gay| 中日韩在线观看视频| 日韩高清影视在线观看| 成人欧美一区二区三区黑人一| 亚洲国产综合视频在线观看| 黄色一级视频免费观看| 久久亚洲风情| 欧美专区在线播放| 亚洲人成五月天| 少妇毛片一区二区三区| 色综合色综合久久综合频道88| 超碰97人人干| 777欧美精品| 色综合天天综合网天天狠天天| 亚洲精品国产无套在线观| 狠狠操精品视频| 日韩欧美亚洲国产精品字幕久久久| 亚洲人123区| 国偷自产av一区二区三区麻豆| 看片网址国产福利av中文字幕| 国产成人极品视频| 午夜黄色小视频| 欧美日一区二区在线观看| 久久一区二区三区av| 国产91在线视频蝌蚪| 男人的天堂网av| 欧美波霸videosex极品| 国产午夜久久av| 亚洲在线观看免费视频| 先锋影音av在线| 中文字幕亚洲成人| 亚洲国产中文字幕| 欧美一区亚洲二区| 日日骚久久av| 亚洲视频在线二区| 国产一区二区三区高清在线观看| 女同性αv亚洲女同志| 亚洲男女在线观看| 国产精品久久久久久久av| 777电影在线观看| 污污的网站在线免费观看| 欧美一区二区三区免费视| 国产精品乱看| 国产av人人夜夜澡人人爽麻豆| 久久av一区二区三区| 日韩一区二区三区在线观看| 日韩欧美国产系列| 香蕉视频在线网址| 日本10禁啪啪无遮挡免费一区二区| 天堂av在线免费观看| 欧美一级片在线播放| 妞干网福利视频| 久久久久久一区二区三区四区别墅| 免费一级特黄特色大片| 免费国产亚洲视频| 少妇bbbb搡bbbb| 亚洲男人天堂2021| 两性午夜免费视频| 国产精品成人一区| 欧美午夜精品久久久久久久| 99久久国产综合精品色伊| 国产一区二区按摩在线观看| 成人性生交大片免费观看嘿嘿视频| 成人视屏在线观看| 日本一区二区免费不卡| 日韩欧美美女在线观看| 一个人看的视频www在线观看免费| 日韩中文字幕在线免费观看| 性鲍视频在线观看| 国产精品视频福利| 欧美性受xxxx黑人爽| 国产精品一区牛牛影视| 快播电影网址老女人久久| 国产精品久久精品| 欧美极品在线播放| 在线成人激情| 日日干天天干| 欧美国产一区二区在线| 一区免费视频| 日韩一区二区三区在线视频| 国产精品无码人妻一区二区在线| 欧美色图免费看| www.中文字幕.com| 亚洲一卡二卡三卡四卡| 国产又白又嫩又紧又爽18p| 欧美一级高清片| 亚洲精品人成网在线播放影院| 成人女人免费毛片| 天天影视网天天综合色在线播放| 亚洲免费av一区| 亚洲女人视频| 日本不卡视频一区二区| 欧美日韩成人免费观看| 亚洲精品无码久久久| 精品无码国产一区二区三区av| 精品国产一区二区三区性色av| 羞羞在线观看视频| 少妇一区视频| 久久精品aⅴ无码中文字字幕重口| 国偷自拍第113页| 5g影院5g电影天天爽快| 99这里都是精品| 国产精品初高中精品久久| 日日摸天天爽天天爽视频| 日韩国产欧美三级| 91成人免费| 日产精品久久久久| 青青草成人免费视频| 欧美精品丝袜久久久中文字幕| 日韩精品一区二区三区视频| 亚洲成人国产综合| 日韩国产高清一区| 中文精品99久久国产香蕉| 在线a视频网站| 国产免费a级片| 日本香蕉视频在线观看| 国产高潮国产高潮久久久91| 97人人做人人爽香蕉精品| 国产亚洲欧美日韩一区二区| 另类高清dbsm日本tvav| 日韩乱码一区二区三区| 亚洲色图19p| 成人a区在线观看| 亚洲国产精品久久久久秋霞不卡| 久久99久久99精品免视看婷婷| 国产欧美一区二区三区沐欲| 18禁网站免费无遮挡无码中文| 国产精品一区二区三区美女| 国偷自产av一区二区三区麻豆| 一本色道久久88综合亚洲精品ⅰ| 国产精品三区在线观看| 免费观看黄一级视频| 苍井空张开腿实干12次| 性xxxx奶大欧美高清| 欧美精品一二三区| 国产亚洲精品美女久久久m| 你懂得视频网站| 色av中文字幕一区| 狠狠色丁香婷婷综合影院| 成人在线视频播放| 99热免费在线| 在线中文字幕日韩| 欧美三日本三级少妇99| 精品久久久久久亚洲综合网| 亚洲欧美日韩国产成人综合一二三区| 欧美精品午夜| 黄色在线资源| 激情久久av| 欧美精品视频www在线观看| 中文字幕国产传媒| 九九视频精品免费| 在线观看午夜看亚太视频| 97视频在线免费观看| 综合欧美精品| 亚洲精品国产一区二| 中文字幕精品视频| 波多野结衣一区二区三区在线| 久久久国产精品黄毛片| 久艹在线免费观看| 精品一区三区| 欧美男女视频| 成人激情免费视频| 亚洲综合第一区| 欧美日韩在线电影| 久久99国产精品久久久久久久久| 在线中文字幕-区二区三区四区| 久久精品久久精品亚洲人| 999视频精品| 日韩一区欧美小说| 日韩国产欧美区| 国产一区二区三区在线观看精品| 影音先锋中文在线视频| 亚洲成人三区| 亚洲精品中文在线观看| 日韩亚洲一区二区| 国产免费黄视频| 亚洲最新视频在线| 亚洲精品美女久久7777777| 中文字幕一区二区三区在线乱码| 亚洲高清视频在线| 国产熟女一区二区三区五月婷| 成人av免费电影网站| 精品国产免费第一区二区| 国产高清视频免费最新在线| 亚洲成熟女性毛茸茸| 亚洲国产日韩综合一区| 国产精品香蕉国产| 思思99精品视频在线观看| 国产人妻人伦精品1国产丝袜| 四虎精品成人免费观看| 亚洲自拍偷拍网址| 欧美人乱大交xxxxx| 国产激情偷乱视频一区二区三区| 欧美精品国产白浆久久久久| 九色丨porny丨| 亚洲综合色在线| 成人国产免费视频| 亚洲日本欧美中文幕| 999国产精品999久久久久久| 91综合网人人| 香蕉视频禁止18| 国产91成人在在线播放| 精品亚洲a∨| 色悠久久久久综合网小说| 性国裸体高清亚洲| 国产日韩欧美一区二区三区乱码| 奇米色777欧美一区二区| 蜜臀va亚洲va欧美va天堂| 五月激情婷婷综合| 欧美精品vⅰdeose4hd| 欧美日韩成人综合天天影院| 免费男女羞羞的视频网站中文版| 99久热在线精品视频观看| 韩国无码av片在线观看网站| 国产成人精品视频| 成人国产在线观看| 成人综合在线网站| 黑人巨大精品欧美黑白配亚洲| 国产精品一区二区91| 在线看欧美日韩| 欧美日本精品一区二区三区| 资源av在线| 那种视频在线观看| 日韩av一区二区三区在线| av黄在线观看| 国产精品第一页在线观看| 亚洲制服欧美久久| 日韩精品人妻中文字幕| 亚洲欧洲三级| 国产三级久久久| 久久久精品国产| 最近中文字幕免费mv| 五月天网站亚洲| 久久久这里只有精品视频| 国产美女视频一区二区二三区| 小说区图片区色综合区| 欧美高清激情视频| 超碰在线一区二区三区| 国产精品入口66mio| 色综合www| 91精品国产综合久久香蕉麻豆| 草裙成人精品一区二区三区| 国产成人无码精品久久二区三| 久久99精品国产.久久久久久| 东北少妇不带套对白| 久久精品成人欧美大片免费|