及時通訊最佳實務

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

描述

Lhttp是一個基於websocket服務端架構,提供一個類似http的協議去協助開發人員開發長連線應用程式。

使用Lhttp可以大量減少服務端開發的工作量,實現非常好的模組化和業務功能的解耦合。

可以定製任何你想要的功能。

項目地址

特點

  • 使用簡單,功能強大

  • 效能高,使用gnatsd訊息佇列 publish 10000 條訊息耗時0.04s(single-core CPU,1G memory).

  • 支援叢集,橫向擴充,通過增加伺服器來擷取更高的服務能力

  • 非常容器進行定製與擴充

  • 可以非常好的與http服務協同工作,如利用http發送訊息,將訊息轉寄給上遊http伺服器等。所以即便你不會go語言也可以開發一些應用。

聊天室demo

前端sdk

協議棧:

+--------------------+|       lhttp        |+--------------------+|     websocket      |+--------------------+|        TCP         |+--------------------+

系統架構

        +---------------------------------------+        |    message center cluster (gnatsd)    |        +---------------------------------------+ ........|.................|...............|..................| +-------------+   +-------------+   +-------------+        | | |lhttp server |   |lhttp server |   |lhttp server |   ...  |  lhttp 服務叢集| +-------------+   +-------------+   +-------------+        |  .....|..........._____|  |___.............|  |_________......      |          |            |            |            |       <----使用websocket連結 +--------+  +--------+   +--------+   +--------+   +--------+    | client |  | client |   | client |   | client |   | client |    +--------+  +--------+   +--------+   +--------+   +--------+  

快速入門

go get github.com/nats-io/natsgo get github.com/fanux/lhttp

先啟動gnatsd:

cd bin./gnatsd &./lhttpd 

開啟另一個終端,執行用戶端程式,輸入命令碼:

cd bin./lhttpClient

使用docker快速體驗

$ docker build -t lhttp:latest .$ docker run -p 9090:9090 -p 8081:8081 lhttp:latest

開啟瀏覽器,訪問: http://localhost:9090.

開啟兩個視窗就可以聊起來了。

websocket 連接埠是 8081, 可以使用自己的websocket用戶端去連 ws://localhost:8081

也可以從dockerhub上下載鏡像:

$ docker run -p 9090:9090 -p 8081:8081 fanux/lhttp:latest

協議介紹

LHTTP/1.0 Command\r\n                --------起始行,協議名和版本,Command:非常重要,標識這條訊息的命令碼是什麼,服務端也是根據命令碼註冊對應的處理器的。Header1:value\r\n                    --------首部Header2:value\r\n\r\nbody                                 --------訊息體

案例:

LHTTP/1.0 chat\r\n                  命令碼叫`chat`content-type:json\r\n               訊息體使用json編碼publish:channel_jack\r\n            服務端請把這條訊息publish給jack (jack訂閱了channel_jack)\r\n{    to:jack,    from:mike,    message:hello jack,    time:1990-1210 5:30:48}

使用教程,只需三步

定義你的處理器,需要彙總 BaseProcessor

type ChatProcessor struct {    *lhttp.BaseProcessor}

實現三個介面,串連開啟時幹嘛,關閉時幹嘛,訊息到來時幹嘛。

type ChatProcessor struct {}func (p ChatProcessor)OnOpen(h *WsHandler) {    //your logic}func (p ChatProcessor)OnClose(h *WsHandler) {    //your logic}func (p ChatProcessor)OnMessage(h *WsHandler) {    //your logic}

註冊你的處理器,這裡的chat 與訊息體中的chat對應,也就是這個處理器僅會處理LHTTP/1.0 chat\r\n....這類訊息.

lhttp.Regist("chat",&ChatProcessor{&lhttp.BaseProcessor{}})

如果命令碼是 "chat" ChatProcessor 會處理它。

這裡比如收到訊息就直接將訊息返回:

func (p *ChatProcessor)OnMessage(h *WsHandler) {    h.Send(h.GetBody())}

啟動伺服器

http.Handler("/echo",lhttp.Handler(lhttp.StartServer))http.ListenAndServe(":8081")

一個完整的回射例子:

type ChatProcessor struct {    *lhttp.BaseProcessor}func (p *ChatProcessor) OnMessage (h *lhttp.WsHandler) {    log.Print("on message :", h.GetBody())    h.Send(h.GetBody())}func main(){    lhttp.Regist("chat", &ChatProcessor{&lhttp.BaseProcessor{}})    http.Handle("/echo",lhttp.Handler(lhttp.StartServer))    http.ListenAndServe(":8081",nil)}

訂閱/發布

下面來看用Lhttp開發及時通訊應用有多簡單

假設有兩個用戶端,這裡的用戶端比如瀏覽器應用。

client1:

LHTTP/1.0 command\r\nsubscribe:channelID\r\n\r\nbody optional

client1通過websocket向Lhttp發送如上字串,就訂閱了channelId

client2:

LHTTP/1.0 command\r\npublish:channelID\r\n\r\nbody require

client2通過websocket向Lhttp發送如上字串,就向channelID發布了一條訊息。 因為client1訂閱了channelID,所以client1會收到這條訊息。

client1不想再收訊息,那麼發如下字串給服務端即可:

LHTTP/1.0 command\r\nunsubscribe:channelID\r\n\r\nbody optional

訂閱/發布 是lhttp內建功能,服務端一行代碼不用寫即可擷取這種服務,只需要使用特定首部subscribe,publishunsubscribe

同時訂閱多個,如同時訂閱多個聊天室。

LHTTP/1.0 chat\r\nsubscribe:channelID1 channelID2 channelID3\r\n\r\n

使用http發布訊息

URL: /publish .
方法: POST .
http body: 整個lhttp訊息
for example I want send a message to who subscribe channel_test by HTTP.
如我想發送一條訊息給訂閱了channel_test的人。

    resp,err := http.POST("https://www.yourserver.com/publish", "text/plain",    "LHTTP/1.0 chat\r\npublish:channel_test\r\n\r\nhello channel_test guys!")

這裡封裝好了一個更好用的工具 Publish tools.go

//func Publish(channelID []string, command string, header map[string]string, body string) (err error) {//}//send message to who subscribe mike.Publish("mike", "yourCommand", nil, "hello mike!")

上遊伺服器

upstream首部可以讓lhttp向上遊的http伺服器發送一條訊息。

LHTTP/1.0 command\r\nupstream:POST http://www.xxx.com\r\n\r\nbody

如果是POST方法,lhttp會把整個訊息體當作http的body發送給 http://www.xxx.com
如果是GET,lhttp會忽略訊息體

LHTTP/1.0 command\r\nupstream:GET http://www.xxx.com?user=user_a&age=26\r\n\r\nbody

upstream有什麼用:

如我們不想改動lhttp的代碼,但是想儲存聊天記錄。

通過upstream可以實現很好的解耦:

並且http server可以用其它語言實現.

        +----+                  +----+        |jack|                  |mike|        +----+                  +----+         |_____________    _______|                       |  |                   +------------+                   |lhttp server|                   +------------+                         |(http request with chat record)                         V                   +------------+                   | http server|  upstream server(http://www.xxx.com/record)                   +------------+                   (save chat record)    

jack:

LHTTP/1.0 chat\r\nupstream:POST http://www.xxx.com/record\r\npublish:channel_mike\r\n\r\nhello mike,I am jack

mike:

LHTTP/1.0 chat\r\nsubscribe:channel_mike\r\n\r\n

這樣jack publish訊息時不僅mike可以收到,後端的upstream server也可以收到,我們可以在後端伺服器中處理訊息儲存的邏輯,如將訊息

儲存到redis的有序集合中。

分塊訊息

試想一下,一條訊息中既有圖片也有文字還有語音怎麼辦? lhttp的multipart首部解決這個問題

LHTTP/1.0 upload\r\nmultipart:0 56\r\n\r\ncontent-type:text/json\r\n\r\n{filename:file.txt,fileLen:5}content-type:text/plain\r\n\r\nhello
content-type:text/json\r\n\r\n{filename:file.txt,fileLen:5}content-type:text/plain\r\n\r\nhello^                                                          ^|<---------------------first part------------------------->|<---------second part------------>|0                                                          56                           

http中是使用boundry實現的,lhttp使用位移量標識分塊,這樣效率更高,不需要遍曆整個訊息體。

如何擷取分塊訊息

如用戶端訊息如下:

LHTTP/1.0 upload\r\nmultipart:0 14\r\n\r\nk1:v1\r\n\r\nbody1k2:v2\r\n\r\nbody2

服務端代碼,訊息存在鏈表中:

type UploadProcessor struct {    *lhttp.BaseProcessor}func (*UploadProcessor) OnMessage(ws *lhttp.WsHandler) {    for m := ws.GetMultipart(); m != nil; m = m.GetNext() {        log.Print("multibody:", m.GetBody(), " headers:", m.GetHeaders())    }}//don't forget to tegist your command processorlhttp.Regist("upload", &UploadProcessor{&lhttp.BaseProcessor{}})

首部過濾模組開發

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.