android通信协议,Android通信

Android通信方式篇(七)-Binder机制(Native层(下))

本篇文章针对向ServiceManager注册服务 和 获取服务两个流程来做总结。在这两个过程中,ServiceManager都扮演的是服务端,与客户端之间的通信也是通过Binder IPC。

德兴网站建设公司创新互联公司,德兴网站设计制作,有大型网站制作公司丰富经验。已为德兴近1000家提供企业网站建设服务。企业网站搭建\外贸网站制作要多少钱,请找那个售后服务好的德兴做网站的公司定做!

在此之前先了解下Binder的进程与线程的关系:

用户空间 :ProcessState描述一个进程,IPCThreadState对应一个进程中的一个线程。

内核空间 :binder_proc描述一个进程,统一由binder_procs全局链表保存,binder_thread对应进程的一个线程。

ProcessState与binder_proc是一一对应的。

Binder线程池 :每个Server进程在启动时会创建一个binder线程池,并向其中注册一个Binder线程;之后Server进程也可以向binder线程池注册新的线程,或者Binder驱动在探测到没有空闲binder线程时会主动向Server进程注册新的的binder线程。对于一个Server进程有一个最大Binder线程数限制15,(#define DEFAULT_MAX_BINDER_THREADS 15)。对于所有Client端进程的binder请求都是交由Server端进程的binder线程来处理的。我的理解是:binder线程是进程进行binder ipc时的一条数据处理路径。

MediaPlayerService向ServiceManager注册过程如下:

相关类:

整个过程总结如下:

1 获取BpServiceManager 与 BpBinder

由defaultServiceManager()返回的是BpServiceManager,同时会创建ProcessState对象和BpBinder对象。然后通过BpBinder执行transact,把真正工作交给IPCThreadState来处理。

2 BpBinder transact

Binder代理类调用transact()方法,真正工作还是交给IPCThreadState来进行transact工作。

3 通过IPCThreadState 包装并转换数据并进行transact事务处理

每个线程都有一个IPCThreadState,每个IPCThreadState中都有一对Parcel变量:mIn、mOut。相当于两根数据管道:

最后执行talkWithDriver。

writeTransactionData:将BC Protocol + binder_transaction_data结构体 写入mOut, 然后执行waitForResponse:

由talkWithDriver将数据进一步封装到binder_write_read结构体,通过ioctl(BINDER_WRITE_READ)与驱动通信。同时等待驱动返回的接收BR命令,从mIn取出返回的数据。

mIn包装的数据结构(注册服务handle = 0 ,code 为ADD_SERVICE_TRANSACTION):

4 Binder Driver

把binder_write_read结构体write_buffer里数据取出来,分别得到BC命令和封装好数据的事务binder_transaction_data, 然后根据handler,在当前binder_proc中,找到相应的binder_ref,由binder_ref再找到目标binder_node实体,由目标binder_node再找到目标进程binder_proc。然后就是插入数据:当binder驱动可以找到合适的线程,就会把binder_transaction节点插入到servciemanager的线程的todo队列中,如果找不到合适的线程,就把节点之间插入servciemanager的binder_proc的todo队列。

5 ServiceManager

经过Binder Driver的处理,数据已经到了ServiceManager进程,在BR_TRANSACTION的引导下,在binder_loop()中执行binder_parser()取出数据,执行do_add_service()操作,最终向 svcinfo 列表中添加已经注册的服务(没有数据的返回)。最后发送 BR_REPLY 命令唤醒等待的线程,通知注册成功。结束MediaPlayerService进程 waitForResponse()的状态,整个注册过程结束。

获取服务的过程与注册类似,首先 ServiceManager 向 Binder 驱动发送 BC_TRANSACTION 命令携带 CHECK_SERVICE_TRANSACTION 命令,同时获取服务的线程进入等待状态 waitForResponse()。Binder 驱动收到请求命令向 ServiceManager 的发送 BC_TRANSACTION 查询已注册的服务,会区分请求服务所属进程情况。

查询到直接响应 BR_REPLY 唤醒等待的线程。若查询不到将与 binder_procs 链表中的服务进行一次通讯再响应。

以startService为例来简单总结下执行流程:

3.1 从方法执行流程来看:

Client :

1 AMP.startService 标记方法以及通过Parcel包装数据;

2 BinderProxy.transact 实际调用native的 android_os_BinderProxy_transact 传递数据;

3 获取BpServiceManager 与 BpBinder 同时会创建ProcessState。然后通过BpBinder执行transact,把真正工作交给IPCThreadState来处理;

4 IPC.transact 主要执行writeTransactionData,将上层传来的数据重新包装成binder_transaction_data,并将BC Protocol + binder_transaction_data结构体 写入mOut;

5 IPC waitForResponse talkWithDriver + 等待返回数据;

6 talkWithDriver 将数据进一步封装成binder_write_read,通过ioctl(BINDER_WRITE_READ)与驱动通信;

Kernel :

7 binder ioctl 接收BINDER_WRITE_READ ioctl命令;

8 binder_ioctl_write_read 把用户空间数据ubuf拷贝到内核空间bwr;

9 binder_thread_write 当bwr写缓存有数据,则执行binder_thread_write;当写失败则将bwr数据写回用户空间并退出;

10 binder_transaction 找到目标进程binder_proc并插入数据到目标进程的线程todo队列,最终执行到它

时,将发起端数据拷贝到接收端进程的buffer结构体;

11 binder_thread_read 根据binder_transaction结构体和binder_buffer结构体数据生成新的binder_transaction_data结构体,写入bwr的read_buffer,当bwr读缓存有数据,则执行binder_thread_read;当读失败则再将bwr数据写回用户空间并退出;最后,把内核数据bwr拷贝到用户空间ubuf。

12 binder_thread_write + binder_ioctl BR命令和数据传递

Server:

13 IPC.executeCommand 解析kernel传过来的binder_transaction_data数据,找到目标BBinder并调用其transact()方法;

14 IPC.joinThreadPool 采用循环不断地执行getAndExecuteCommand()方法, 处理事务。当bwr的读写buffer都没有数据时,则阻塞在binder_thread_read的wait_event过程. 另外,正常情况下binder线程一旦创建则不会退出.

15 BBinder.transact 到Binder.exeTransact 调用 AMN.onTransact

16 AMN.onTransact 把数据传递到AMS.starService去执行

17 AMS.starService Server处理了Client的请求了

然后原路replay回去,talkWithDriver 到Kernel ,然后找到Client进程,把数据拷贝到read_buffer里,最终唤醒IPC,把反馈传递回AMP.startService。完成启动服务。

3.2 从通信协议流程来看:

非oneWay:

oneway:

oneway与非oneway区别: 都是需要等待Binder Driver的回应消息BR_TRANSACTION_COMPLETE. 主要区别在于oneway的通信收到BR_TRANSACTION_COMPLETE则返回,而不会再等待BR_REPLY消息的到来. 另外,oneway的binder IPC则接收端无法获取对方的pid.

3.3 从数据流来看

从用户空间开始:

进入驱动后:

回到用户空间:

参考:

Android网络请求知识(三)授权,TCP/IP,HTTPS建立过程

由身份或持有的令牌确认享有的权限,登录过程实质上的目的也是为了确认权限。

Cookie是客户端给服务器用的,setCookie是服务器给客户端用的。cookie由服务器处理,客户端负责存储

客户端发送cookie:账户和密码

服务端收到后确认登录setCookie:sessionID=1,记下sessionID

客户端收到sessionID后记录,以后请求服务端带上对比记录下sessionID,说明已经登录

会话管理:登录状态,购物车

个性化:用户偏好,主题

Tracking:分析用户行为

XXS:跨脚本攻击,及使用JavaScript拿到浏览器的cookie之后,发送到自己的网站,以这种方式来盗用用户Cookie。Server在发送Cookie时,敏感的Cookie加上HttpOnly,这样Cookie只能用于http请求,不能被JavaScript调用

XSRF:跨站请求伪造。Referer 从哪个网站跳转过来

两种方式:Basic和Bearer

首先第三方网站向授权网站申请第三方授权合作,拿到授权方颁发的client_id和client_secret(一般都是appid+appkey的方式)。

在这就过程中申请的client_secret是服务器持有的,安全起见不能给客户端,用服务端去和授权方获取用户信息,再传给客户端,包括④,⑤的请求过程也是需要加密的。这才是标准的授权过程。

有了access_token之后,就可以向授权方发送请求来获取用户信息

步骤分析就是上面的内容,这里把第4,6,8请求的参数分析一下

第④步参数:

response_type:指授权类型,必选,这里填固定值‘code’

client_id:指客户端id,必选,这里填在平台报备时获取的appid

redirect_uri:指重定向URI,可选

scope:指申请的权限范围,可选

state:指客户端当前状态,可选,若填了,则认证服务器会原样返回该值

第⑥步参数:

grant_type:指使用哪种授权模式,必选,这里填固定值‘authorization_code’

code:指从第⑤步获取的code,必选

redirect_uri:指重定向URI,必选,这个值需要和第④步中的redirect_uri保持一致

client_id:指客户端id,必选,这里填在平台报备时获取的appid

client_secret:指客户端密钥,必选,这里填在平台报备时获取的appkey

第⑧步参数:

access_token:指访问令牌,必选,这里填第⑦步获取的access_token

token_type:指令牌类型,必选,大小写不敏感,bearer类型 / mac类型

expires_in:指过期时间,单位秒,当其他地方已设置过期时间,此处可省略该参数

refresh_token:指更新令牌,可选,用即将过期token换取新token

scope:指权限范围,可选,第④步中若已申请过某权限,此处可省略该参数

我们在上面的第八步中会有refresh_token的参数,这个在实际操作中也比较常见

有时候我们在自己的项目中,将登陆和授权设计成类似OAuth2的过程,不过去掉Authorization code。登陆成功返回access_token,然后客户端再请求时,带上access_token。

我们常常会说到TCP/IP,那到底是什么呢。这就需要讲到网络分层模型。TCP在传输层,IP在网络层。那为什么需要分层?因为网络不稳定,导致需要重传的问题。为了提高传输效率我们就需要分块,在传输层中就会进行分块。TCP还有两个重要的内容就是三次握手,四次分手。

HTTPS 协议是由 HTTP 加上TLS/SSL协议构建的可进行加密传输、身份认证的网络协议,主要通过数字证书、加密算法、非对称密钥等技术完成互联网数据传输加密,实现互联网传输安全保护

1.客户端通过发送Client Hello报文开始SSL通信。报文中包含客户端支持的SSL的指定版本、加密组件列表(所使用的加密算法及密钥长度),客户端随机数,hash算法。

2.服务器可进行SSL通信时,会以Server Hello报文作为应答。和客户端一样,在报文中包含SSL版本以及加密组件,服务端随机数。服务器的加密组件内容是从接收到客户端加密组件内筛选出来的。

3.之后服务器发送Certificate报文。报文中包含公开密钥证书。一般实际有三层证书嵌套,其实像下面图二直接用根证书机构签名也是可以的,但是一般根证书机构比较忙,需要类似中介的证书机构来帮助。

4.最后服务器发送Server Hello Done报文通知客户端,最初阶段的SSL握手协商部分结束。

5.SSL第一次握手结束后,客户端以Client Key Exchange报文作为回应。报文中包含通信加密中使用的一种被称为Pre-master secret的随机密码串。该报文已用步骤3中的公开密钥进行加密。

6.接着客户端继续发送Change Cipher Spec报文。该报文会提示服务器,在此报文之后的通信会采用Pre-master secret密钥加密。

7.客户端发送Finished报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确解密报文作为判定标准。

8.服务器同样发送Change Cipher Spec报文。

9.服务器同样发送Finished报文。

10.服务器和客户端的Finished报文交换完毕之后,SSL连接就算建立完成。当然,通信会受到SSL的保护。从此处开始进行应用层协议的通信,即发送HTTP响应。

11.应用层协议通信,即发送HTTP响应。

12.最后由客户端断开连接。断开连接时,发送close_notify报文。这步之后再发送TCP FIN报文来关闭与TCP的通信。

利用客户端随机数,服务端随机数,per-master secret随机数生成master secret,再生成客户端加密密钥,服务端加密密钥,客户端MAC secert,服务端MAC secert。MAC secert用于做报文摘要,这样能够查知报文是否遭到篡改,从而保护报文的完整性。

Android网络请求知识(一)HTTP基础概念

Android网络请求知识(二)对称和非对称加密、数字签名,Hash,Base64编码

Android网络请求知识(三)授权,TCP/IP,HTTPS建立过程

Android socket通信协议的封装和解析

android socket通信协议的封装和解析,其实是和java一样的,都是通过http中的相关知识来封装和解析,主要是通过多次握手,如下代码:

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.io.PrintWriter;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Main {

private static final int PORT = 9999;

private ListSocket mList = new ArrayListSocket();

private ServerSocket server = null;

private ExecutorService mExecutorService = null; //thread pool

public static void main(String[] args) {

new Main();

}

public Main() {

try {

server = new ServerSocket(PORT);

mExecutorService = Executors.newCachedThreadPool();  //create a thread pool

System.out.println("服务器已启动...");

Socket client = null;

while(true) {

client = server.accept();

//把客户端放入客户端集合中

mList.add(client);

mExecutorService.execute(new Service(client)); //start a new thread to handle the connection

}

}catch (Exception e) {

e.printStackTrace();

}

}

class Service implements Runnable {

private Socket socket;

private BufferedReader in = null;

private String msg = "";

public Service(Socket socket) {

this.socket = socket;

try {

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

//客户端只要一连到服务器,便向客户端发送下面的信息。

msg = "服务器地址:" +this.socket.getInetAddress() + "come toal:"

+mList.size()+"(服务器发送)";

this.sendmsg();

} catch (IOException e) {

e.printStackTrace();

}

}

@Override

public void run() {

try {

while(true) {

if((msg = in.readLine())!= null) {

//当客户端发送的信息为:exit时,关闭连接

if(msg.equals("exit")) {

System.out.println("ssssssss");

mList.remove(socket);

in.close();

msg = "user:" + socket.getInetAddress()

+ "exit total:" + mList.size();

socket.close();

this.sendmsg();

break;

//接收客户端发过来的信息msg,然后发送给客户端。

} else {

msg = socket.getInetAddress() + ":" + msg+"(服务器发送)";

this.sendmsg();

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 循环遍历客户端集合,给每个客户端都发送信息。

*/

public void sendmsg() {

System.out.println(msg);

int num =mList.size();

for (int index = 0; index  num; index ++) {

Socket mSocket = mList.get(index);

PrintWriter pout = null;

try {

pout = new PrintWriter(new BufferedWriter(

new OutputStreamWriter(mSocket.getOutputStream())),true);

pout.println(msg);

}catch (IOException e) {

e.printStackTrace();

}

}

}

}    

}

网站题目:android通信协议,Android通信
文章来源:https://www.cdcxhl.com/article40/dsdcjho.html

成都网站建设公司_创新互联,为您提供网页设计公司自适应网站搜索引擎优化移动网站建设网站策划外贸网站建设

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

成都定制网站网页设计