最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Python編寫一個簡單的服務(wù)注冊發(fā)現(xiàn)服務(wù)器

 更新時間:2023年04月21日 08:24:21   作者:真的不能告訴你我的名字  
我們都知道有很多的非常著名的注冊服務(wù)器,例如:?Consul、ZooKeeper、etcd,甚至借助于redis完成服務(wù)注冊發(fā)現(xiàn)。但是本篇文章我們將使用python?socket寫一個非常簡單的服務(wù)注冊發(fā)現(xiàn)服務(wù)器,感興趣的可以了解一下

我們都知道有很多的非常著名的注冊服務(wù)器,例如: Consul、ZooKeeper、etcd,甚至借助于redis完成服務(wù)注冊發(fā)現(xiàn)。但是本篇文章我們將使用python socket寫一個非常簡單的服務(wù)注冊發(fā)現(xiàn)服務(wù)器。

本篇文章所依賴的環(huán)境為:

案例展示

項目地址:

gitee: gitee.com/pdudo/golearn/blob/master/python/registerCenter/registerSer.py

該服務(wù)注冊服務(wù)器,沒有使用第三方庫,可以復(fù)制到本地,使用python registerSer.py啟動即可,啟動成功后,會輸出“注冊服務(wù)器已經(jīng)啟動...”的信息。

該案例使用的協(xié)議是TCP協(xié)議,為了防止粘包,客戶端在發(fā)送消息的時候,使用CRLF進行區(qū)分,服務(wù)器是按照讀取到CRLF進行分割的,服務(wù)數(shù)據(jù),均采用json格式,共支持注冊服務(wù)、查詢服務(wù)、銷毀服務(wù)。

對應(yīng)的json為:

注冊服務(wù):

{"type":"register","key":"redis","values":"123456@127.0.0.1:6379","timeout":"30"}

注冊和更新服務(wù)都是用的上述報文,其中type 是告訴服務(wù)器需要做什么,register代表注冊服務(wù),keyvalues是注冊服務(wù)的名稱和注冊服務(wù)的值,最后的timeout是存活時間,單位是秒,若超過這個時間沒有更新服務(wù),則自動銷毀該服務(wù)。

如果客戶端發(fā)送的信息沒有攜帶time,則注冊存活時間為30s。

查詢服務(wù):

{"type":"query","key":"redis"}

{"type":"query","key":"all"}

查詢服務(wù)使用的typequery,查詢的key若是all則是查詢?nèi)?,其他則是查詢值為key的服務(wù)信息。

銷毀服務(wù):

{"type":"destruction","key":"redis"}

銷毀服務(wù)的typedestruction,key為需要銷毀服務(wù)的名稱。

目前還暫不支持登錄驗證。

案例測試

由于該注冊服務(wù)報文采用的是使用CRLF進行分割,所以可以直接使用telnet進行模擬注冊,為了方便,我們還是使用python來寫這個測試,代碼如下:

上述代碼,我們需要自己指定\r\n進行分割,我們指定了4個注冊,以及等待5s再進行查詢,最后再銷毀了一個服務(wù)。

運行結(jié)果如下:

可以看到上述結(jié)果,第一個輸出是我們注冊的消息,而后我們等待了5秒,目的是為了等redis服務(wù)因為超時被自動銷毀,而后再進行查詢,就沒有redis2的注冊信息了,接著我們銷毀了mysql1的服務(wù),整個測試完畢。

如何來寫一個注冊發(fā)現(xiàn)服務(wù)器

我們想要寫一個注冊服務(wù)器,我們至少需要知道以下幾個知識點:

  • 服務(wù)注冊發(fā)現(xiàn)核心是啥?
  • 應(yīng)用層數(shù)據(jù)報文應(yīng)該如何定義。
  • 如何從tcp數(shù)據(jù)流中按條獲取記錄。

服務(wù)器發(fā)現(xiàn)核心是啥

python中,我們可以通過定義一個字典,來存儲所有注冊信息,例如:

{
        "redis": {
        "value": "123456@127.0.0.1:6379",
        "timeout":30,
        "lastUpdateTime": time.time()
        },
        "redis1": {....}
}

我們只需要維護好這個字典,就可以做到最基本的服務(wù)注冊和服務(wù)發(fā)現(xiàn)了。

報文如何定義

該服務(wù),我們使用的是json來定義的數(shù)據(jù)報文,按照type區(qū)分,分別為:

  • register: 注冊或更新服務(wù)。
  • query: 查詢服務(wù)。
  • destruction銷毀服務(wù)。

json中,以keyvalue來確定服務(wù)名稱和服務(wù)值,還有一個timeout來定義超時銷毀時間。

例如:

{"type":"register","key":"redis1","values":"123456@127.0.0.1:6379","timeout":"30"}
{"type":"query","key":"all"}
{"type":"destruction","key":"mysql1"}

如何從tcp流中獲取記錄

如何從tcp中讀取需要的記錄呢?

這個點其實核心是如何解決tcp粘包,我們都知道,tcp socket也被稱之為數(shù)據(jù)流,就是因為一旦三次握手之后,數(shù)據(jù)就像水龍頭一樣源源不斷流動,我們不知道哪兒是頭,哪兒是尾巴。

所以需要指定一個結(jié)束符,告知程序,讀到哪兒,一條記錄就讀完了,這里我們每條信息都發(fā)送一個\r\n來作為結(jié)束符。

編寫注冊發(fā)現(xiàn)服務(wù)器

如何從tcp流中讀取數(shù)據(jù)

要解決粘包,有2種方法,第一種是定義特殊字段分隔符,例如: \r\n當(dāng)讀到\r\n的時候,就判斷一條消息結(jié)束了。

例如,如圖:

我們發(fā)送了一條記錄,hello world如何判斷結(jié)束了呢? 在最后面加一個\r\n,當(dāng)程序讀到的時候,就判斷這條消息接收完了,就可以了。

還有一種方法是,提前計算發(fā)送的字節(jié)數(shù),然后記錄到行首,每次讀取的時候,先讀取行首的個數(shù),而后更具個數(shù)再讀取數(shù)據(jù),例如:

我們提前計算hello world字符串占用多少個字節(jié),而后再在行首分n個字節(jié)來存儲個數(shù),例如我們使用2個字節(jié)來存儲,存儲數(shù)據(jù)為10。

我們這篇服務(wù)發(fā)現(xiàn)使用的是第一種方法。

那要如何判斷\r\n呢?可以參考如下代碼:

data = b""
while True:
    data += client.recv(1)
    if data.endswith(b"\r\n"):
        break
data = data[:len(data)-2]

上述代碼中,我們先定義了一個空的byte,變量名為data,而后每次讀取1個字節(jié),再判斷是否以\r\n結(jié)尾,如果是以\r\n結(jié)尾的話,就跳出循環(huán),跳出循環(huán)后,我們需要刪除掉\r\n所以會有data = data[:len(data)-2]這個語句,這樣的話,我們就成功拿到了記錄。

數(shù)據(jù)包如何區(qū)分類型

上個段落,我們已經(jīng)拿到了一條數(shù)據(jù)包,那么我們這個服務(wù)有3種操作,分別是 查詢、注冊、銷毀,如何客戶端發(fā)上來的請求呢? 其實如之前所述,我們可以通過type來定義,操作流程為:

  • 解析客戶端發(fā)上來的json信息。
  • 判斷其type類型。

整合為語句的話,可以理解為這樣:

上述代碼,我們先使用json.loads序列化為json格式,而后根據(jù)type信息區(qū)分是注冊服務(wù)、銷毀服務(wù)還是其查詢服務(wù)。這里注意的是,若json字符串都沒有type或者key類型,則證明該數(shù)據(jù)包有問題,直接拒絕掉即可。如果不是上述三種服務(wù)類型的話,那也證明包有問題,直接拒絕即可。

服務(wù)注冊

服務(wù)注冊,需要獲取客戶端傳上來的keyvalues信息,若沒有的話,則證明該包有問題,而后判斷其timeout是否攜帶,若沒有攜帶的話,則定義為默認值30s,而后將該值入早已定義好的字典類型中即可,代碼如下:

這里,需要注意的是,我們再更新服務(wù)信息的時候,會將lastUpdateTime更新到目前的時間戳,方便后續(xù)查詢服務(wù)的時候做惰性刪除。

服務(wù)銷毀

服務(wù)銷毀,核心點是刪除字典中的記錄即可,為了避免拋錯,還是要檢查客戶端傳上來的json字符串是否攜帶key,雖然在前面檢查過,這個再檢查一下,還是有必要的。

銷毀服務(wù),就直接刪除字典的該記錄就可以,如果傳入的值,在該字典中沒有記錄的話,默認為銷毀完畢。

代碼如下:

服務(wù)查詢

服務(wù)查詢,客戶端發(fā)上來的還是以key為主,若key的值為all的話,則查詢所有服務(wù),若不為all的話,則查詢單個服務(wù)注冊的信息,這里在查詢的時候,是將服務(wù)超時銷毀一起做了的,采用的是惰性刪除,當(dāng)查詢到該值的是,它會比對超時時間,若已經(jīng)超時了,則直接刪除該對象,代碼如下:

上述查詢到key后,會做一次超時檢測,若超時了,則刪除該記錄的值,若沒有超出時間,再返回信息。

總結(jié)

該篇文章,介紹了如何使用python socket寫一個服務(wù)注冊發(fā)現(xiàn),該項目還是有很多不完美的地方,比如: 沒有對字典進行加鎖、內(nèi)存數(shù)據(jù)沒有落地等等。但是可以將它理解為一個初始的demo。

該篇文章由于篇幅和時間關(guān)系,所以寫的更多的是思路,應(yīng)該如何如何才能完成這個項目,而沒有對詳細的語法進行梳理,比如 如何開一個多線程來服務(wù)多個客戶端等,這個后面有時間再詳細介紹。

到此這篇關(guān)于基于Python編寫一個簡單的服務(wù)注冊發(fā)現(xiàn)服務(wù)器的文章就介紹到這了,更多相關(guān)Python服務(wù)注冊發(fā)現(xiàn)服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

沁水县| 宁蒗| 雷波县| 普兰县| 杭州市| 正蓝旗| 井研县| 台北市| 宝清县| 城固县| 拜城县| 松桃| 禹州市| 辽中县| 江西省| 凤翔县| 抚远县| 新民市| 平安县| 长乐市| 蓬莱市| 溆浦县| 万盛区| 上栗县| 新巴尔虎右旗| 定陶县| 罗平县| 六安市| 阜平县| 满洲里市| 新巴尔虎左旗| 仁化县| 黔南| 华安县| 廉江市| 兴业县| 台南县| 唐海县| 礼泉县| 麦盖提县| 阿克苏市|