zoukankan      html  css  js  c++  java
  • Android : App通过LocalSocket 与 HAL间通信

      LocalSocket其通信方式与Socket差不多,只是LocalSocket没有跨越网络边界。对于*nix系统来说,“一切皆为文件”,Socket也不例外,Socket按照收发双方的媒介来说有三种类型:

      1,通过网络端口: 即通过本地回环接口(即LoopBack)127.0.0.1来收发数据;

      2,通过文件系统: 通过文件作为收发数据的中转站;

      3,通过内存映射文件:在内存中开辟一块区域作为收发数据的中转站,此区域仍然使用文件读写API进行访问;

      LocalSocket支持方式2和方式3。

    以下通过HAL层(c)作为server,App端(java)作为client,进行LocalSocket通信演示(核心部分代码):

    C代码:

        J_U8* sName="nano_server_socket";
        J_Int server_sockfd, client_sockfd;  
        J_Int server_len, client_len;
        J_Int reuse = 1;
        J_Int err;
       struct sockaddr_un server_address; /*声明一个UNIX域套接字结构*/  
        struct sockaddr_un client_address;  
    
        unlink (sName); /*删除原有server_socket对象*/
    
        /*创建 socket, 通信协议为AF_LOCAL, SOCK_STREAM 数据方式*/    
        server_sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
        if(server_sockfd < 0){
            ALOGE("server_sockfd error : %s
    ",strerror(errno));
            return;
        }
    
        /*配置服务器信息(socket对象路径)*/
        // Check with length +1 for the *initial* ''.
        if ((strlen(sName) + 1) > sizeof(server_address.sun_path)) {
            ALOGE("name too long
    ");
            goto EXIT;
        }
    
        /*
         * Note: The path in this case is *not* supposed to be
         * ''-terminated. ("man 7 unix" for the gory details.)
         */    
         server_address.sun_path[0] = 0;
         memcpy(server_address.sun_path + 1, sName, strlen(sName));
    
         /*配置服务器信息(通信协议)*/  
         server_address.sun_family = AF_LOCAL;
    
         /*默认设置resue FLAG*/
         if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
             ALOGE("reuse error
    ");
             goto EXIT;
         }
    
        /*配置服务器信息(服务器地址长度)*/  
        client_len = server_len = strlen(sName) + offsetof(struct sockaddr_un, sun_path) + 1;
    
        /*绑定 socket 对象*/  
        bind (server_sockfd, (struct sockaddr *)&server_address, server_len);  
          
        /*监听网络,队列数为1*/  
        if(listen(server_sockfd,1)<0){
            ALOGE("listen error : %s
    ",strerror(errno));
            goto EXIT;
        }
        /*接受客户端请求; 第2个参数用来存储客户端地址; 第3个参数用来存储客户端地址的大小*/    
        /*建立(返回)一个到客户端的文件描述符,用以对客户端的读写操作*/  
        client_sockfd = accept (server_sockfd, (struct sockaddr *)&client_address, (socklen_t *)&client_len);
       if (client_sockfd == -1) { ALOGE("accept error : %s ",strerror(errno)); goto EXIT; } else if (client_sockfd> FD_SETSIZE){ ALOGE("accept reach max "); close(client_sockfd); goto EXIT; }
       /*start read loop*/ 
       while(1) {

          char buf[1024]={0};
          ssize_t res=read(client_socketfd,buf,sizeof(buf));

          ALOGD("server get data : %s", buf);

          if(res <=0){
            if(errno == EAGAIN)
              continue;
            ALOGE("errno %s ",strerror(errno));
            close(client_socketfd);
            return;
           }

        }

    EXIT:
        close(server_sockfd);

    HAL层可具体参考Android源码的 systemtosisrcsocket_utils 目录下的 socket_local_client.cc 和 socket_local_server.cc 代码(Android 8.0),

    直接调用如下封装好的接口即可:

    /***********/
    /***服务端***/
    /**********/
    /*(1)创建server socket接收client端数据*/    
    server_sockfd = osi_socket_local_server("server_socket",ANDROID_SOCKET_NAMESPACE_ABSTRACT,SOCK_STREAM); 
    /*(2)等待client端连接*/
    client_sockfd = accept (server_sockfd, NULL, NULL);
    /*(3)数据读取线程*/
    while(1){
        ssize_t res=read(client_sockfd ,buf,sizeof(buf));
    }  
    
    /***********/
    /***客户端***/
    /**********/
    /*(1)创建client socket */    
    client_sockfd = osi_socket_local_client("client_socket",ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
    /*(2)发送数据到server端 */    
    write(client_sockfd, "hello", strlen("hello"));

    JAVA代码:

    package com.example.administrator.localsocket;
    
    import android.net.LocalServerSocket;
    import android.net.LocalSocket;
    import android.net.LocalSocketAddress;
    import android.os.Bundle;
    import android.os.RemoteException;
    import android.support.design.widget.FloatingActionButton;
    import android.support.design.widget.Snackbar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.util.Log;
    import android.view.View;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.Toast;
    
    import java.io.IOException;
    
    import static android.widget.Toast.LENGTH_SHORT;
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String SOCKET_ADDRESS = "nano_server_socket"; //和HAL层统一地址名称
    
        LocalSocket client_socket = null;
        LocalSocketAddress addr;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            client_socket = new LocalSocket(); //创建socket对象
            addr = new LocalSocketAddress(SOCKET_ADDRESS,LocalSocketAddress.Namespace.ABSTRACT); //使用虚空间地址
            try {
                client_socket.connect(addr);  //请求连接
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            findViewById(R.id.sendMsg).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    try {
                        //发送数据
                        String data="hello";
                        client_socket.getOutputStream().write(data.getBytes());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
       }
    @Override
    protected void onStop() { super.onStop(); try { client_socket.close(); } catch (IOException e) { e.printStackTrace(); } } }

    :Android8.0版本验证app端要用LocalSocket,需要两个条件:

       1.apk需要签名成platform_app; (方法可参考: https://www.cnblogs.com/blogs-of-lxl/p/9233285.html )

       2.需要给platform_app增加selinux权限,修改xxxsepolicyplatform_app.te,添加如下两条规则:

        typeattribute platform_app mlstrustedsubject;
        allow platform_app audioserver:unix_stream_socket connectto;

    测试结果:

  • 相关阅读:
    OpenLayers 添加OpenStreetMap(OSM)瓦片层示例
    [转]Net Framework引路蜂地图开发示例
    SVG关注复杂图形的网页绘制技术
    解决Easyui1.3.3 IE8兼容性问题
    Ajax学习教程在线阅读
    判断访问站点的浏览器类型
    修改TOMCAT服务器图标为应用LOGO
    ArcGIS学习推荐基础教程摘录
    Jquery html页面处理基础
    android AppWidget的使用以及利用TimerTask实现widget的定时更新
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/9236076.html
Copyright © 2011-2022 走看看