java socket跨进程通信,Android跨进程通信-socket

Socket的使用和原理

socket套接字本来是设计给基于TCP/IP协议的网络通信使用的,但由于它是一种C/S架构模型,即客户端服务器端架构,这种模型能带来很大的安全性以及快速的响应能力,所以也常常用在进程之间的通信上。

Socket的使用方式比上面前面提到的其他IPC都要复杂很多,我们先通过下图了解它的使用流程。

3486e218ed5d

236c1533b78642b5bf5e3d6c5959b12e_tplv-k3u1fbpfcp-zoom-1.png

我们在看看具体的函数

#include

#include

#include

int socket(int protofamily, int type, int protocol);//创建socket

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//绑定socket

int listen(int sockfd, int backlog);//监听端口号

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//客户端请求建立连接

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//服务端接收连接请求

ssize_t send(int sockfd, const void *buf, size_t len, int flags); //IO写函数

ssize_t recv(int sockfd, void *buf, size_t len, int flags);//IO读函数

int close(int fd); //关闭函数

Linux系统中万物皆文件,所以Socket也是一个虚拟文件,socket文件的数据结构中包含了当前主机的ip地址,当前主机进程的端口号,发送端主机的ip地址等信息,通过这些信息,我们可以在虚拟文件系统中唯一定位到一个Socket文件,通过对这个文件的读写达到通信的目的。

Socket在Android系统中的使用场景

当我们使用socket来进行进程间的通信时,实际是通过将IP设置为127.0.0.1这个本地IP来实现的,Android系统为我们提供了LocalSocket来进行进程间的通信,LocalSocket的实质也是对Socket的封装,通过直接使用LocalSocket,我们省掉了设置本机IP等一系列繁琐的操作。

我们看一个LocalSocket的使用场景:当我们启动一个App应用时,如果当前的应用的进程不存在,AMS会通过Socket通知Zygote去Fork新进程。

//文件-->frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

// 服务端

public static void main(String argv[]) {

ZygoteServer zygoteServer = new ZygoteServer();

……

zygoteServer.registerServerSocket(socketName);

……

Log.i(TAG, "Accepting command socket connections");

zygoteServer.runSelectLoop(abiList);

zygoteServer.closeServerSocket();

……

}

ZygoteInit启动时,会创建一个ZygoteServer,然后fork生成System Server进程,接着启动整个Framwork的Server,最终执行zygoteServer的runSelectLoop函数,始终等待其他进程发送过来的fork进程的消息。

我们接着看registerServerSocket函数和runSelectLoop函数的实现

//文件-->/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

void registerServerSocket(String socketName) {

if (mServerSocket == null) {

int fileDesc;

final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;

try {

String env = System.getenv(fullSocketName);

fileDesc = Integer.parseInt(env);

} catch (RuntimeException ex) {

throw new RuntimeException(fullSocketName + " unset or invalid", ex);

}

try {

FileDescriptor fd = new FileDescriptor();

fd.setInt$(fileDesc);

mServerSocket = new LocalServerSocket(fd);

} catch (IOException ex) {

throw new RuntimeException(

"Error binding to local socket '" + fileDesc + "'", ex);

}

}

}

void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {

ArrayList fds = new ArrayList();

ArrayList peers = new ArrayList();

fds.add(mServerSocket.getFileDescriptor());

peers.add(null);

while (true) {

StructPollfd[] pollFds = new StructPollfd[fds.size()];

for (int i = 0; i < pollFds.length; ++i) {

pollFds[i] = new StructPollfd();

pollFds[i].fd = fds.get(i);

pollFds[i].events = (short) POLLIN;

}

try {

Os.poll(pollFds, -1);

} catch (ErrnoException ex) {

throw new RuntimeException("poll failed", ex);

}

for (int i = pollFds.length - 1; i >= 0; --i) {

if ((pollFds[i].revents & POLLIN) == 0) {

continue;

}

if (i == 0) {

ZygoteConnection newPeer = acceptCommandPeer(abiList);

peers.add(newPeer);

fds.add(newPeer.getFileDesciptor());

} else {

boolean done = peers.get(i).runOnce(this);

if (done) {

peers.remove(i);

fds.remove(i);

}

}

}

}

}

可以看到registerServerSocket函数实际是创建了LocalServerSocket,这个LocalServerSocket的名字就叫“zygote”,runSelectLoop函数将ServerSocket加入多路复用模型里,当收到消息时便调用runOnce方法去fork进程。

//文件-->/frameworks/base/core/java/android/os/Process.java

//客户端

public static final ProcessStartResult start(final String processClass,

final String niceName,

int uid, int gid, int[] gids,

int debugFlags, int mountExternal,

int targetSdkVersion,

String seInfo,

String abi,

String instructionSet,

String appDataDir,

String invokeWith,

String[] zygoteArgs) {

return zygoteProcess.start(processClass, niceName, uid, gid, gids,

debugFlags, mountExternal, targetSdkVersion, seInfo,

abi, instructionSet, appDataDir, invokeWith, zygoteArgs);

}

//文件-->/frameworks/base/core/java/android/os/ZygoteProcess.jav

public final Process.ProcessStartResult start(final String processClass,

final String niceName,

int uid, int gid, int[] gids,

int debugFlags, int mountExternal,

int targetSdkVersion,

String seInfo,

String abi,

String instructionSet,

String appDataDir,

String invokeWith,

String[] zygoteArgs) {

try {

return startViaZygote(processClass, niceName, uid, gid, gids,

debugFlags, mountExternal, targetSdkVersion, seInfo,

abi, instructionSet, appDataDir, invokeWith, zygoteArgs);

} catch (ZygoteStartFailedEx ex) {

Log.e(LOG_TAG,

"Starting VM process through Zygote failed");

throw new RuntimeException(

"Starting VM process through Zygote failed", ex);

}

}

private Process.ProcessStartResult startViaZygote(final String processClass,

final String niceName,

final int uid, final int gid,

final int[] gids,

int debugFlags, int mountExternal,

int targetSdkVersion,

String seInfo,

String abi,

String instructionSet,

String appDataDir,

String invokeWith,

String[] extraArgs)

throws ZygoteStartFailedEx {

……

synchronized(mLock) {

//连接服务端socket,并发送数据

return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

}

}

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {

if (primaryZygoteState == null || primaryZygoteState.isClosed()) {

try {

primaryZygoteState = ZygoteState.connect(mSocket);

} catch (IOException ioe) {

throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);

}

}

……

}

public static ZygoteState connect(String socketAddress) throws IOException {

DataInputStream zygoteInputStream = null;

BufferedWriter zygoteWriter = null;

final LocalSocket zygoteSocket = new LocalSocket();

zygoteSocket.connect(new LocalSocketAddress(socketAddress,

LocalSocketAddress.Namespace.RESERVED));

zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

zygoteWriter = new BufferedWriter(new OutputStreamWriter(

zygoteSocket.getOutputStream()), 256);

return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,

Arrays.asList(abiListString.split(",")));

}

private static Process.ProcessStartResult zygoteSendArgsAndGetResult(

ZygoteState zygoteState, ArrayList args)

throws ZygoteStartFailedEx {

int sz = args.size();

for (int i = 0; i < sz; i++) {

if (args.get(i).indexOf('\n') >= 0) {

throw new ZygoteStartFailedEx("embedded newlines not allowed");

}

}

final BufferedWriter writer = zygoteState.writer;

final DataInputStream inputStream = zygoteState.inputStream;

writer.write(Integer.toString(args.size()));

writer.newLine();

for (int i = 0; i < sz; i++) {

String arg = args.get(i);

writer.write(arg);

writer.newLine();

}

writer.flush();

Process.ProcessStartResult result = new Process.ProcessStartResult();

result.pid = inputStream.readInt();

result.usingWrapper = inputStream.readBoolean();

if (result.pid < 0) {

throw new ZygoteStartFailedEx("fork() failed");

}

return result;

}

从上面的代码实现可以看到,当AMS调用Process的start()函数时,最终执行到了ZygoteProcess类中的openZygoteSocketIfNeeded() 函数,连接socket,然后调用zygoteSendArgsAndGetResult() 函数通过LocalSocket 往LocalServerSocket发送消息 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值