新潮測試平臺--慎用 PRC 返回的資料 (二)

池小波發表於2020-04-17

該文原創為新潮質量保障技術團隊中的 “上進的中年軟體測試從業者”,用於技術交流分享

上一篇給自己立了一個flag,這周內把測試平臺-慎用PRC返回的資料(一)的第二篇文章發出來,原本的計劃是在公司周天下午開員工大會時來寫好。結果今天下午發了通知出來,本週天的員工大會取消,另行通知。那麼問題來了,我是週五晚上寫完,還是週末在家寫。為了週末過得純粹一點,還是決定現在就開始寫。

昨天晚上在西瓜視訊看到一個自媒體作者在說自己為什麼能夠成功,第一個是堅持,第二個是研究了抖音的智推機制,還有一個是親力親為,不管是拍攝、剪輯、後期製作還是運營。每天一早上起來想的就是今天的拍攝主題是什麼。所以如果不知道怎麼做,何不如參照成功的案例呢。

開篇

之前我們講到了如何更方便的使用RPC服務端返回的Response,核心就是序列化的過程。

為了探索RPC服務端在通訊過程中是如何區別對待不同型別資料的,我們開始去研究原始碼。不知道大佬們都怎麼追原始碼(相對層級比較多的),我的方式相對就非常的簡單粗暴,直接根據返回的各種有用的資訊,在原始碼包裡面全域性搜尋,藉助Pycharm可以非常便利的定位到想到的資訊,還可以藉助grepWin進行硬碟掃描,當然grepWin更適合的場景是查詢包含某些特性關鍵字的檔案。

調研

從服務端返回的字典型別的,那我們就直接通過關鍵字“<netref class ”進行搜尋,然後就發現了:

class NetrefMetaclass(type):
slots = ()

def repr(self):
if self.module:
return "" % (self.module, self.name)
else:
return "" % (self.name,)

repr是做什麼的,與str有什麼區別,感興趣的可以去搜一下看看。然後經過一系列的追蹤NetrefMetaclass->BaseNetref->class_factory->netref模組->???->???, 然後就沒有然後了。也就是根本不知道追到哪裡去了。

感謝偉大的百度和廣大的愛好者,找到了另外一種可以Google的穩定方式,避免廣告嫌疑,自行百度(一鍵指令碼搭建科學上網Trojan梯子(自建***)詳細教程)。然後Google搜了一遍,最後決定放棄,不想再分析了。

過了幾天無意看到之前開啟的一個rpyc官網,看到了一個非常重要的資訊介紹,也就是我們上一篇提到的box, 下圖是官網的原文。

根據上面的介紹,我們知道了有些時候服務端是直接返回值的(By Value), 有些時候是直接返回引用(By Reference)。這是一個很重要的突破,那我們就可以通過所謂的Box設計來追蹤究竟什麼情況下會By Value, 什麼情況下會By Reference。然後就順利的找到了box方法:

def _box(self, obj): # boxing
if brine.dumpable(obj):
return consts.LABEL_VALUE, obj
if type(obj) is tuple:
return consts.LABEL_TUPLE, tuple(self._box(item) for item in obj)
elif isinstance(obj, netref.BaseNetref) and obj.____conn__ is self:
return consts.LABEL_LOCAL_REF, obj.____id_pack__

根據上面的程式碼,我們猜測:

- 如果obj可以被dump, 那麼直接返回。

- 否則會返回reference。

為什麼這樣做?

根據官網的介紹,如下:

也就是RPC的機制並不能傳輸除位元組和文字以外的物件,所以只能傳遞reference,也就是需要用的時候,再去呼叫。

至此,原理搞清楚了,但是還是沒有從呼叫過程上面來找到完整的呼叫鏈路。

解決

考慮到以後還是會經常的去檢視原始碼,純手動去追蹤鏈路過程太繁瑣,然後就Google找到了一種呼叫關係追蹤過程trace,具體的命令如下:

python -m trace --ignore-dir=.../lib/python3.7 --trace test.py >result.txt

然後我們就發現了非常全面的根據記錄:

結語

trace同樣支援管道過濾,可以過濾出自己關心的檔案,也可以忽略追蹤的路徑。除了trace還有很多開源的工具,也可以很方便的追蹤執行過程,後續我們會寫一篇關於呼叫過程的追蹤。

今天就介紹到這裡,或許能安心的過個週末,或許也不一定。誰又知道呢。

相關文章