Android中LocalSocket(套接字)使用

来源:互联网 发布:阿里云客服报名关闭 编辑:程序博客网 时间:2024/06/05 22:32

今天在看《Android框架揭秘》的第5章《Zygote》时,Zygote在初始化时,会调用registerZygoteSocket()来接收新的Android应用程序运行的请求,

从字面来理解是传统的Socket使用,但个人觉得不应该是,特地找资料学习了一下,下面的介绍比较详细到位。

又进一步了解一下,使用的其实是UDS(Unix Domain Socket),详细的介绍如下:

    linux操作系统提供了一种UNIX域协议的进程间通信方式,它不能应用在网络中,能使用在本机两进程间的通信中。它能方便的向两个非亲属关系的进程间传递文件描述符,效果类似于在父子进程间传递一样。UNIX域套接字在和本地进程进行交互时候效率更高,因为它不需要处理网络异常可能。
    socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。
    UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。
    使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。
    UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

 

原文链接:http://www.cnblogs.com/bastard/archive/2012/10/09/2717052.html

 一 Socket

  Socket最初用在基于TCP/IP网络间进程通信中,以客户端/服务器模式进行通信。

实现异步操作,共享资源集中处理,提高客户端响应能力。

Tcp通信基本流程:

  服务器端 客户端

  1.创建socket 1.创建socket

  2.bind()

  3.listen()

  4.accecp()

  ----等待客户端连接---- 2.connect()

  5.读数据(recv) 3.写数据(send)

  6.写数据(send) 4.读数据(recv)

  7.关闭socket(closesocket()) 5.关闭socket(closesocket())

数据流:

    

二 Android LocalSocket

LocalSocket

  在Unix域名空间创建一个套接字(非服务端)。

  是对Linux中Socket进行了封装,采用JNI方式调用,实现进程间通信。

  具体就是Native层Server和Framework层Client之间进行通信,或在各层次中能使用Client/Server模式实现通信。

LocalServerSocket

  创建服务器端Unix域套接字,与LocalSocket对应。

LocalSocketImpl

Framework层Socket的实现,通过JNI调用系统socket API。

LocalSocketAddress

Unix域socket的地址以及所处的空间。

JNI访问接口:\frameworks\base\core\jni\android_net_LocalSocketImpl.cpp

  socket_create

  socket_connect_local

  socket_bind_local

  socket_listen

  ……

下面看看这几个类之间的关系:

    

使用Android的LocalSocket建立socket通信,是基于网络socket过程一致的。

三 native与framework之间的通信

以install这个服务为例:

1 增加socket资源

\system\core\rootdir\init.rc中:

  service installd /system/bin/installd

class main

socket installd stream 600 system system

在启动install服务时,就会为install分配socket文件系统资源:dev/socket/installd

Install服务的Socket资源和名称installd绑定起来。

这些都是在开机初始化化init进程中启动service时完成:

  service_start

  create_socket

  publish_socket

2 native层

install进程 建立服务端程序

native 层中作为server:\frameworks\base\cmds\installd\installd.c

[cpp] view plaincopyprint?
  1. <span style="font-family:Microsoft YaHei;">int main(const int argc, const char *argv[])   
  2. {  
  3.     //获取已绑定socket  
  4.     lsocket = android_get_control_socket(SOCKET_PATH);  
  5.   
  6.     //监听socket  
  7.     listen(lsocket, 5);  
  8.   
  9.     for (;;) {  
  10.         //等待客户端建立连接  
  11.         s = accept(lsocket, &addr, &alen);  
  12.         for (;;) {  
  13.                  //接收数据 相当于recv  
  14.                  readx(s, buf, count);  
  15.   
  16.                  //执行相关的操作  
  17.                 execute(s, buf);  
  18.         }  
  19.   
  20.         //关闭socket  
  21.         close(s);  
  22.     }  
  23. }</span>  

3 framework层

客户端程序:

\frameworks\base\services\java\com\android\server\pm\Installer.java

[java] view plaincopyprint?
  1. <span style="font-size:12px;"><span style="font-family:Microsoft YaHei;">boolean connect()   
  2. {  
  3.        //创建socket  
  4.        mSocket = new LocalSocket();  
  5.   
  6.        //设置连接地址  
  7.        LocalSocketAddress address = new             LocalSocketAddress("installd",  
  8.                     LocalSocketAddress.Namespace.RESERVED);  
  9.   
  10.        //建立连接  
  11.        mSocket.connect(address);  
  12.   
  13.        //获取数据输入流 可以读数据  
  14.        mIn = mSocket.getInputStream();  
  15.   
  16.        //获取数据输出流 可以写数据  
  17.        mOut = mSocket.getOutputStream();  
  18. }</span></span>  

 

因此以native层service与framework建立client/server模式socket通信主要代码:

java层主要代码:

[java] view plaincopyprint?
  1. <span style="font-size:12px;"><span style="font-family:Microsoft YaHei;">LocalSocket s =null;  
  2.     LocalSocketAddress l;  
  3.   
  4.        s = new LocalSocket();  
  5.        l = new LocalSocketAddress(SOCKET_NAME,  
  6.       LocalSocketAddress.Namespace.RESERVED);  
  7.        s.connect(l);</span></span>  

native层主要代码:

[java] view plaincopyprint?
  1. <span style="font-family:Microsoft YaHei;">    s_fdListen = android_get_control_socket(SOCKET_NAME);  
  2.     ret = listen(s_fdListen, n);  
  3.     s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);</span>  

init.rc中加入:

[cpp] view plaincopyprint?
  1. <span style="font-family:Microsoft YaHei;">service myserver /system/bin/myserver  
  2.        class main  
  3.        socket myserver stream 600 system system  
  4.        ……</span>  

  当然建立这种client/server模式并不一定要在native层和framework层,仅在framework层也能够进行。

系统提供了LocalSocket作为客户端使用,同时提供了LocalServerSocket作为服务端使用。

Zygote服务使用了LocalServerSocket作为服务端socket通信。

  建立socket通信,也可以在代码执行过程中进行,使用LocalSocket与LocalServerSocket。

在init.rc中为服务端建立的socket资源和初始化时绑定,与在代码中使用LocalServerSocket

建立的服务端socket资源在Linux域空间不同而已,过程是一样的跟一般的socket通信过程一致。

四 LocalSocket与LocalServerSocket建立socket通信

  LocalSocket就是作为客户端建立于服务端的连接,发送数据。

  LocalServerSocket作为服务端使用,建立socket监听客户端请求。通过构造函数看到有两种方式:

在Linux抽象空间 创建一个新的服务端socket:

[java] view plaincopyprint?
  1. <span style="font-family:Microsoft YaHei;">public LocalServerSocket(String name) throws IOException{        //创建socket资源  
  2.         impl = new LocalSocketImpl();        impl.create(true);        //绑定地址  
  3.         localAddress = new LocalSocketAddress(name);  
  4.         impl.bind(localAddress);        //监听        impl.listen(LISTEN_BACKLOG);  
  5. }</span>  

用文件描述符创建已经存在并且绑定的服务端socket:

  如在init.rc中指定socket资源 dev/socket/……,zygote使用此方式创建作为服务端的socket

  LocalServerSocket socket = new LocalServerSocket(createFileDescriptor(fileDesc));

[java] view plaincopyprint?
  1. <span style="font-size:12px;"><span style="font-family:Microsoft YaHei;">public LocalServerSocket(FileDescriptor fd) throws IOException{        //已绑定 监听  
  2.        impl = new LocalSocketImpl(fd);  
  3.        impl.listen(LISTEN_BACKLOG);  
  4.        localAddress = impl.getSockAddress();  
  5. }  
  6. </span></span>  


通常使用过程中:

客户端代码:

[java] view plaincopyprint?
  1. <span style="font-family:Microsoft YaHei;">String message;//创建socketLocalSocket sender = new LocalSocket();//建立对应地址连接  
  2. sender.connect(new LocalSocketAddress(SOCKET_ADDRESS));//发送写入数据  
  3. sender.getOutputStream().write(message.getBytes());//关闭socket  
  4. sender.getOutputStream().close();</span>  


服务端:

[java] view plaincopyprint?
  1. <span style="font-family:Microsoft YaHei;">//创建socket并绑定监听 新创建的  
  2. LocalServerSocket server = new LocalServerSocket(SOCKET_ADDRESS);  
  3. while (true) {  
  4.   //等待建立连接  LocalSocket receiver = server.accept();  //接收获取数据流  
  5.   InputStream input = receiver.getInputStream();  
  6.   ……  
  7. }</span>  

UDS(Unix Domain Socket)的进一步了解,可以参考此文:
http://blog.csdn.net/bingqingsuimeng/article/details/8574869
0 0
原创粉丝点击