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=, 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的更多相关文章
- ATX 学习 (四)-atxserver2
ATXSERVER2 一.main()文件启动 1.首先通过parse_args返回一个Namespace作一些配置,登录页html在SimpleLoginHandler这个里边写着,2.接着通过db ...
- andriod 学习三 使用android资源
3.1 android框架中有许多资源,包括布局,字符串,位图,图片....,使用资源之前需要在相应的资源文件中定义资源,然后编译程序时ADT将定义的资源转换成java类并给予唯一的id,而代码中需要 ...
- Android开发学习之路--Content Provider之初体验
天气说变就变,马上又变冷了,还好空气不错,阳光也不错,早起上班的车上的人也不多,公司来的同事和昨天一样一样的,可能明天会多一些吧,那就再来学习android吧.学了两个android的组件,这里学习下 ...
- 【ATX学习大纲】【ATX基于uiautomator2+Python学习】之Android自动化
github学习地址:https://github.com/openatx/uiautomator2 <_io.TextIOWrapper name='<stderr>' mode= ...
- 三、Android学习第三天——Activity的布局初步介绍(转)
(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 三.Android学习第三天——Activity的布局初步介绍 今天总结下 ...
- Android Sip学习(三)Android Voip实现
Android Sip学习(三)Android Voip实现 Android Sip学习(准备知识)SIP 协议完整的呼叫流程 Android Sip学习(一)Android 2.3 APIs S ...
- Android JNI学习(三)——Java与Native相互调用
本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...
- 【Flutter学习一】Android的App的三种开发方式
是时候学习新技术了: 转自:https://blog.csdn.net/qq_41346910/article/details/86692124 移动开发发展到现在,已经出现了三种开发方式.本文我将为 ...
- Android学习五:Content Provider 使用
1ContentProvider相关知识1.1在安卓应用中,通过文件方式对外共享数据,需要进行文件操作读写数据:采用sharedpreferences共享数据,需要使用sharedpreference ...
随机推荐
- HASH的应用(负数下标用偏移量解决)
Input 每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n个处于区间[-500000,500000]的整数. Output 对每组测试数据按从大到小的 ...
- HDU 1564 找规律博弈
题目大意是: 从n*n的方格角落的一个起点出发,每次移到上下左右一个未曾到达过的位置,谁不能走了谁就输了 想了好久都想不出,看了大神的题解 Orz了 果然博弈不是脑残的游戏啊... 这里从起点出发,将 ...
- java 构造不可变类集的使用方法
首先用到的就是Collections.unmodifiablexxx( set.add("hello"); set.add("insert ...
- iphone原生cookie处理
可以使用NSURLConnection的类来执行HTTP请求,登录该网站,并检索的cookie. 要执行一个请求,只是创建一个NSURLConnection的实例,并分配给它的委托对象. NSURLR ...
- Swap Nodes in Pairs(链表操作)
Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2-&g ...
- 02-js变量学习
<html> <head> <title>js的变量学习</title> <meta charset="UTF-8"/> ...
- springboot技术
一 我们为什么要用SpringBoot? 1. SpringBoot核心功能 SpringBoot的核心最足要的功能是自动配置,简单说下springBoot,springboot可以替代额xml配 ...
- 一句话创建Jupyter For TensorFlow
docker run -v /home/jupyter_files:/home/jovyan/work -it -d --rm -p 10082:8888 jupyter/tensorflow-not ...
- symfony 使用原始sql
$this->get('database_connection')->fetchAll('select * from book where book.id=3')
- IEDA-maven引用本地jia包
简单说下为啥用maven引用本地jar包:当在pom文件中配置需要引用了jar的坐标,但是maven引用不了(原因未知情况下),这种情况下就需要找开发提供相关依赖的的jar文件打成一个jar包发送过来 ...