ATX 學習 (三)-atxserver2-android-provider


服務端代碼

代碼clone到本地,搭好相應環境(怎么搭的這里就不介紹了,很好搭的哈)
一般庫首先查看main.py文件,debug模式開始運行

一開始就是沒接觸過的tornado.ioloop,有點偏底層,頭疼,還是加油干吧

為了理解的更深入些,先了解下ioloop的一些知識吧,在這之前先了解點預備知識

一、epoll

ioloop 的實現基於epoll,那么什么是epoll?epoll是Linux內核為處理大批量文件描述
符而作了改進的 poll。那什么是poll呢?首先,我們了解一下, socket 通信時的服務端,當它接受( accept )一個連接並建立通信后( connection )就進行通信,而此時我們並不知道連接的客戶端有沒有信息發完。 這時候有兩種選擇:

  • 一直在這里等着直到收發數據結束;
  • 每隔一定時間來看看這里有沒有數據;

    第二種辦法要比第一種好一些,多個連接可以統一在一定時間內輪流看一遍里面有沒
    有數據要讀寫,看上去可以處理多個連接了,這個方式就是 poll / select 的解決方案。 看起來似乎解決了問題,但實際上,隨着連接越來越多,輪詢所花費的
    時間將越來越長,而服務器連接的 socket大多不是活躍的,所以輪詢所花費的大部分
    時間將是無用的。為了解決這個問題, epoll 被創造出來,它的概念和 poll 類似,不過每次輪詢時,他只會把有數據活躍的socket挑出來輪詢,這樣在有大量連接時輪詢就節省了大量時間。

而對於epoll的操作,其實也很簡單,只要 4 個 API 就可以完全操作它。

epoll_create

用來創建一個 epoll 描述符( 就是創建了一個 epoll )

epoll_ctl

操作 epoll 中的 event;可用參數有:

參數 含義
EPOLL_CTL_ADD 添加一個新的epoll事件
EPOLL_CTL_DEL 刪除一個epoll事件
EPOLL_CTL_MOD 改變一個事件的監聽方式

而事件的監聽方式有七種,而我們只需要關心其中的三種:

宏定義 含義
EPOLLIN 緩沖區滿,有數據可讀
EPOLLOUT 緩沖區空,可寫數據
EPOLLERR 發生錯誤

epoll_wait

就是讓 epoll 開始工作,里面有個參數 timeout,當設置為非 0 正整數時,會監聽(阻塞) timeout 秒;設置為 0 時立即返回,設置為 -1 時一直監聽。

在監聽時有數據活躍的連接時其返回活躍的文件句柄列表(此處為 socket 文件句柄)

close

關閉 epoll

現在簡單了解了 epoll 后,我們就可以來了解ioloop代碼

二 ioloop.py文件

ioloop是tornado的關鍵,是他的最底層。
ioloop就是對I/O多路復用的封裝,它實現了一個單例,將這個單例保存在IOLoop._instance中
主要有兩個要點。一個是configurable機制,一個就是epoll循環

2.1 創建IOLoop實例

來看IOLoop,它的父類是Configurable類,也就是說:IOLoop是一個直屬配置子類
class IOLoop(Configurable):
......
這里就要結合Configurable類進行講解:
Configurable中的new方法
1.首先實例化一個該直屬配置子類的'執行類對象',也就是調用該類的configurable_default方法並返回賦值給impl:

2.2 epoll

從start()開始,啥都不說,上代碼

 

 

asyncio.get_event_loop()方法,在一個coroutine內部獲取loop他不需要將loop作為參數傳遞給協程函數

注意get_event_loop()方法僅在同樣的線程中生效,如果在一個新線程中,應該用new_event_loop()來獲取新的loop,並通過set_event_loop(loop)來將其設為該線程下的loop。
(暫時深入到這里吧,跑偏題了,尷尬)
繼續
main.py文件中運行開始 IOLoop.current().run_sync(async_main)是干什么的

IOLoop中的run_sync方法中調用的函數添加參數,這個好理解。
(這里暫時不在深入,怕又跑偏了,記錄yi有時間的話繼續)

async(協程的語法)

作者很給力,不斷的使用新的東西,這是python3.5后為asyncio提供了async和await的新語法
想要了解協程的可以看下這篇,通過實例來了解更好些https://zhuanlan.zhihu.com/p/25228075
注意:通過async關鍵字定義一個協程(coroutine),協程也是一種對象。協程不能直接運行,需要把協程加入到事件循環(loop),由后者在適當的時候調用協程。
定義異步函數async def async_main()

三 繼續看代碼吧

# 定義異步函數

async def async_main():
        # 建立解析對象ArgumentParser   formatter_class: 重置 help 信息輸出的格式
        parser = argparse.ArgumentParser(
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        # 為應用程序添加參數選項  帶-的為可選參數,default默認參數值
        parser.add_argument(
            '-s', '--server', default='localhost:4000', help='server address')
        # action參數的處理方法
        parser.add_argument(
            "--allow-remote", action="store_true", help="allow remote connect device")
        parser.add_argument(
            '-t', '--test', action="store_true", help="run test code")
        # type參數的數據類型
        parser.add_argument(
            '-p', '--port', type=int, default=3500, help='listen port')
        parser.add_argument("--owner", type=str, help="provider owner email")
        parser.add_argument(
            "--owner-file", type=argparse.FileType("r"), help="provider owner email from file")

 

 

3.1調用parse_args()

來解析ArgumentParser對象中保存的命令行參數:將命令行參數解析成相應的數據類型並采取相應的動作,它返回一個Namespace對象。

args = parser.parse_args()
 
        
 

 

3.2 heartbeat_connect 等待連接

這里直接運行會出現

 


什么原因,應該很容易看到,需要連接localhost:4000,沒有起服務,好吧,先運行rethinkdb數據庫,然后啟動atx-server2

 


好了,然后運行

 

3.3 進入make_app()

使用tornado.web.Application進行路由控制

3.4 heartbeat_connect去連接設備,這里可以看到過程中基本都是異步方法aysc,運行到_connect這個方法時:

async def _connect(self):
      ws = await websocket.websocket_connect(self._server_ws_url)
      ws.__class__ = SafeWebSocket

      await ws.write_message({
          "command": "handshake",
          "name": self._name,
          "owner": self._owner,
          "secret": self._secret,
          "url": self._provider_url,
          "priority": self._priority,  # the large the importanter
      })
 

發現通過websockt 服務來連接

3.5 hbc.open()

IOLoop.current().spawn_callback(coroutine_visit) #開始調用協程
 

3.6 device_watch()

開始使用adb進行監控 127.0.0.1:5037 這里就不再說name多了
_init_binaries() 這里剛開始獲取了設備信息] [設備名] [sdk: 28, abi: arm64-v8a, abis: ['arm64-v8a', 'armeabi-v7a', 'armeabi']
根據設備選擇要使用的atx 代理use atx-agent: atx-agent-armv7

3.7 _install_apk()安裝whatsInput 和ATX這里只看這兩個,另一個屬於測試包

這里手機初始化准備好后會向前端頁面發送
websocket send: {'udid': '2d869e6', 'platform': 'android', 'colding': False, 'provider': {'atxAgentAddress': '127.0.0.1:20001', 'remoteConnectAddress': 'Ip:20004',

'whatsInputAddress': '127.0.0.1:20003'}, 'properties': {'serial': '設備名', 'brand': 'Xiaomi', 'version': '9', 'model': 'MI 9', 'name': 'MI 9'}, 'command': 'update'}

暫時寫到這里吧,明天有時間看下atx-server2的部分代碼,覺得結合着看更方便去了解

目前還在學習中,希望會對大家有所幫助,覺得不錯,就點贊支持一下。 另外,有什么錯誤的地方需要大家指正。謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM