服务端代码

代码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=, 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的部分代码,觉得结合着看更方便去了解

目前还在学习中,希望会对大家有所帮助,觉得不错,就点赞支持一下。 另外,有什么错误的地方需要大家指正。谢谢!

ATX 学习 (三)-atxserver2-android-provider的更多相关文章

  1. ATX 学习 (四)-atxserver2

    ATXSERVER2 一.main()文件启动 1.首先通过parse_args返回一个Namespace作一些配置,登录页html在SimpleLoginHandler这个里边写着,2.接着通过db ...

  2. andriod 学习三 使用android资源

    3.1 android框架中有许多资源,包括布局,字符串,位图,图片....,使用资源之前需要在相应的资源文件中定义资源,然后编译程序时ADT将定义的资源转换成java类并给予唯一的id,而代码中需要 ...

  3. Android开发学习之路--Content Provider之初体验

    天气说变就变,马上又变冷了,还好空气不错,阳光也不错,早起上班的车上的人也不多,公司来的同事和昨天一样一样的,可能明天会多一些吧,那就再来学习android吧.学了两个android的组件,这里学习下 ...

  4. 【ATX学习大纲】【ATX基于uiautomator2+Python学习】之Android自动化

    github学习地址:https://github.com/openatx/uiautomator2 <_io.TextIOWrapper name='<stderr>' mode= ...

  5. 三、Android学习第三天——Activity的布局初步介绍(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 三.Android学习第三天——Activity的布局初步介绍 今天总结下 ...

  6. Android Sip学习(三)Android Voip实现

    Android Sip学习(三)Android Voip实现   Android Sip学习(准备知识)SIP 协议完整的呼叫流程 Android Sip学习(一)Android 2.3 APIs S ...

  7. Android JNI学习(三)——Java与Native相互调用

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  8. 【Flutter学习一】Android的App的三种开发方式

    是时候学习新技术了: 转自:https://blog.csdn.net/qq_41346910/article/details/86692124 移动开发发展到现在,已经出现了三种开发方式.本文我将为 ...

  9. Android学习五:Content Provider 使用

    1ContentProvider相关知识1.1在安卓应用中,通过文件方式对外共享数据,需要进行文件操作读写数据:采用sharedpreferences共享数据,需要使用sharedpreference ...

随机推荐

  1. hihoCoder#1062 最近公共祖先·

    原题地址 A和A的共同祖先是A,即使A没有在之前的家谱中出现过!被这个坑了,WA了很久... 比如:小头爸爸是大头儿子他爹,问:隔壁王叔叔和隔壁王叔叔的最近祖先是谁?,答:隔壁王叔叔. 代码: #in ...

  2. 2018/3/4 Activiti教程之流程部署篇(与Springboot整合版)二

    首先我们来看下Activiti为我们自动生成的这四张用户相关的表 先看下USER表 我已经插入了一些数据,很明显,就是保存用户的信息的 看下GROUP 用户对应的分组信息 MEMBERSHIP 用户和 ...

  3. POJ2586 Y2K Accounting Bug 解题报告

    Description Accounting for Computer Machinists (ACM) has sufferred from the Y2K bug and lost some vi ...

  4. HDU——1285 确定比赛名次

    确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  5. Java电商项目-8.实现SSO单点登陆

    目录 创建ashop-sso-web单点登陆系统 用户名唯一性验证 用户注册 用户登陆 获得用户登陆状态 实现安全退出 项目的Github地址 创建ashop-sso-web单点登陆系统 先创建好模块 ...

  6. NOIP 2010 关押罪犯

    P1525 关押罪犯 题目描述 SS 城现有两座监狱,一共关押着 NN 名罪犯,编号分别为 1-N1−N .他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突. ...

  7. operamasks—omGrid/omBorderLayout的混合使用

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="test.aspx.cs&q ...

  8. JS函数节流代码实现

    函数被频繁调用场景 Js中的函数大多数情况下都是由用户主动调用触发的,一般不会遇到性能相关的问题.但在一些少数情况下,函数的触发不是由用户直接控制.在这些场景下,函数有可能被非常频繁地调用,而造成大的 ...

  9. maven 手动构建项目

    maven 手动构建项目 在空目录下面: D:\test>mvn -B archetype:generate -DarchetypeGroupId=org.apache.maven.archet ...

  10. Tcl学习之--文件操作

    Tcl中文件名称操作遵循Unix/Linux的命名规范. x/y/z表示x文件夹下的y 子文件夹及y以下的子文件夹z. ~admin/email则表示admin用户的email目录. l  file ...