成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用Go實現(xiàn)Redis之二客戶端/服務(wù)端交互

Scliang / 2767人閱讀

摘要:寫在前面在前一篇梳理了版本的基本功能,這一篇要做的是實現(xiàn)客戶端服務(wù)端的交互。進入正題事件處理器既要實現(xiàn)交互,網(wǎng)絡(luò)編程必不可少。

寫在前面

在前一篇梳理了Godis v1.0版本的基本功能,這一篇要做的是實現(xiàn)客戶端/服務(wù)端的交互。先讓代碼跑起來,才算有了生命力。
本篇Godis版本號:v0.0.1

在這個系列文章里,盡量減少介紹Golang語法、C語言語法和redis原理,聚焦在“用Golang實現(xiàn)Redis”的主題上。其中如有疏漏、不足,還請指正。

進入正題 Redis事件處理器

既要實現(xiàn)C/S交互,網(wǎng)絡(luò)編程必不可少。在Redis中,有實現(xiàn)方式:

*Redis基于 Reactor 模式開發(fā)了自己的網(wǎng)絡(luò)事件處理器: 這個處理器被稱為文件事件處理器(file event handler):

文件事件處理器使用 I/O 多路復(fù)用(multiplexing)程序來同時監(jiān)聽多個套接字, 并根據(jù)套接字目前執(zhí)行的任務(wù)來為套接字關(guān)聯(lián)不同的事件處理器。

當被監(jiān)聽的套接字準備好執(zhí)行連接應(yīng)答(accept)、讀?。╮ead)、寫入(write)、關(guān)閉(close)等操作時, 與操作相對應(yīng)的文件事件就會產(chǎn)生, 這時文件事件處理器就會調(diào)用套接字之前關(guān)聯(lián)好的事件處理器來處理這些事件。*

Redis事件處理器的架構(gòu)圖:

Redis兼顧了簡單性和高性能,但出于對其代碼復(fù)雜性的考慮,Godis v0.0.1會采用更簡單的弱智方案。Godis的編碼使用最簡單的同步技術(shù),爭取在網(wǎng)絡(luò)處理方面簡單化,因為復(fù)雜的也不會:)。暫時舍棄高性能,只求可用。在未來的版本中,會結(jié)合Golang自身的特性,優(yōu)化網(wǎng)絡(luò)層。

Godis的方案

客戶端/服務(wù)端的交互,只需使用Golang的net包進行socket編程,編寫一個流程為監(jiān)聽-讀取-處理-回復(fù)的服務(wù)端和一個流程為建立-發(fā)送-接收-顯示的客戶端即可。

圖中英文均為Golang中net包的主要函數(shù),這里簡要說明一下在這一篇中使用的net包函數(shù):
ResolveTCPAddr :
用例:tcpAddr, err := net.ResolveTCPAddr("tcp4", “127.0.0.1:9736”);
功能:創(chuàng)建TCPAddr類型的數(shù)據(jù)結(jié)構(gòu),其中包含IP和Port,留作連接之用;

ListenTCP:
用例:netListen, err := net.Listen("tcp", "127.0.0.1:9763");
功能:監(jiān)聽

Accept:
用例:conn, err := netListen.Accept()
功能:接收請求

Read:
用例:n, err := conn.Read(buff)
功能:讀取數(shù)據(jù)

Write:
用例:conn.Write([]byte(buff))
功能:響應(yīng)數(shù)據(jù)

net.DialTCP:
用例:conn, err := net.DialTCP("tcp", nil, tcpAddr)
功能:建立連接

代碼實現(xiàn)

按照前圖的流程,服務(wù)端的部分代碼如下所示:

func main() {
        netListen, err := net.Listen("tcp", "127.0.0.1:9736")
        if err != nil {
            log.Print("listen err ")
        }
        //checkError(err)
        defer netListen.Close()
    
        for {
            conn, err := netListen.Accept()
            if err != nil {
                continue
            }
            go handle(conn)
        }
    }

真實完整代碼實現(xiàn)請見這里。
在建立客戶端之前,我們通過telnet測試下服務(wù)端是否可用(Redis也支持Telnet方式連接、請求,后面的協(xié)議部分會介紹)。
編譯godis-server.go
go build godis-server.go 并啟動 ./godis-server

執(zhí)行 telnet localhost 9736

可以看到回復(fù)如下:

接下來,按照簡單流程圖的步驟,客戶端的實現(xiàn)如下:

func main() {
    IPPort := "127.0.0.1:9736"

    reader := bufio.NewReader(os.Stdin)
    fmt.Println("Hi Godis")
    tcpAddr, err := net.ResolveTCPAddr("tcp4", IPPort)
    checkError(err)

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

    for {
        fmt.Print(IPPort + "> ")
        text, _ := reader.ReadString("
")
        //清除掉回車換行符
        text = strings.Replace(text, "
", "", -1)
        send2Server(text, conn)

        buff := make([]byte, 1024)
        n, err := conn.Read(buff)
        checkError(err)
        if n == 0 {
            fmt.Println(IPPort+"> ", "nil")
        } else {
            fmt.Println(IPPort+">", string(buff))
        }
    }
}

編譯cli.go 并啟動./cli
與服務(wù)端交互,如下圖所示:

到這里只是實現(xiàn)了基本的客戶端/服務(wù)端通信。接下來為它添加少許交互選項,也就是在執(zhí)行Redis命令行時的選項,讓它看起來更像是Redis。

服務(wù)端添加平滑退出。

未來增加持久化后,會在平滑退出時持久化數(shù)據(jù)到磁盤,防止丟失。
平滑退出這里使用的方式是讓客戶端監(jiān)聽信號,有“退出”信號觸達,做完收尾工作再退出。
簡化代碼如下:

func sigHandler(c chan os.Signal) {
    for s := range c {
        switch s {
        case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
            exitHandler()
        default:
            fmt.Println("signal ", s)
        }
    }
}

func exitHandler() {
    fmt.Println("exiting smoothly ...")
    fmt.Println("bye ")
    os.Exit(0)
}

編譯之后,執(zhí)行Ctrl+c退出,可以看到:

本篇遇到過的問題:

1.服務(wù)端讀取客戶端信息時,發(fā)生err時沒有return,導(dǎo)致服務(wù)端會一直讀取數(shù)據(jù)失敗。
解決方案:return或者其他可以退出goroutine的方案。
本篇就是這樣了。簡陋是簡陋了點,又不是不能用,李姐萬歲。完整代碼請看本篇對應(yīng)的release,(只有release才是當前本篇文章對應(yīng)的完整代碼,當前repo狀態(tài)不是)。

下集預(yù)告
1.[實現(xiàn)get/set命令。][8]

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/28784.html

相關(guān)文章

  • Go實現(xiàn)Redis之一準備工作

    摘要:命令實現(xiàn)命令是最常用的命令之一,也是最能反映緩存發(fā)展歷史的操作。命令在客戶端接收之后,經(jīng)由協(xié)議轉(zhuǎn)換傳遞給服務(wù)端執(zhí)行。服務(wù)端執(zhí)行命令前先查詢是否支持該命令,以決定是否執(zhí)行。,是的簡稱,代表的是只存增量的持久化方式。 緣起 最近公司的第一個PHP轉(zhuǎn)GO項目已經(jīng)在生產(chǎn)環(huán)境穩(wěn)定運行數(shù)周,又逢需求小年兒,最近可以得空分享下去年學(xué)GO過程中的練手項目Godis——用Golang實現(xiàn)的Redis. ...

    zhangke3016 評論0 收藏0
  • Go實現(xiàn)Redis之三get/set命令實現(xiàn)

    摘要:在讀者閱讀實現(xiàn)代碼時,也可以看到最新版本,與有一處是在文件清除掉回車換行符該行被暫時注釋掉,也就是在版本,使用作為文本協(xié)議分隔符,確定命令的結(jié)尾。 寫在前面 本篇Godis版本號:v0.0.2 前一篇文章實現(xiàn)了客戶端/服務(wù)端的交互。這一篇,主要介紹get/set命令的實現(xiàn)。命令本身比較簡單,支撐命令的整個系統(tǒng)基礎(chǔ)比較麻煩。本文會介紹get/set操作涉及的組件和模塊,并適當簡化,最后實...

    Ethan815 評論0 收藏0

發(fā)表評論

0條評論

Scliang

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<