在Android上使用LocalSocket实现上层Java和底层C++的通信


在看Android代码的时候发现有使用LocalSocket,比java本身的socket效率要高,好像没有经过协议栈,是android自己实现的类似共享内存一样的东东,在传输大量数据的时候就需要用到,比如视频数据,在RIL电话那部分也用到。刚好项目用到视频传输,我试用了一把,果然不错!
public static final String SOCKET_ADDRESS = "socket_cmmb_sim_command";//这个名字要记好,在接受端要用到,可以理解为共享内存的设备文件名。
.....

            try {
                LocalServerSocket server = new LocalServerSocket(SOCKET_ADDRESS);
                while (true) {
                    //Log.i(TAG, "begin accept");
                    LocalSocket receiver = server.accept();
                    if (receiver != null) {
                        InputStream input = receiver.getInputStream();

                        byte[] bytes = new byte[4];
                        int size = input.read(bytes, 0, 4);
                        if(size!=4) Log.i(TAG, "received command len:" + String.valueOf(size));

                        int cmd_len = ((bytes[0] & 0xFF) << 24)|((bytes[1] & 0xFF) << 16)
                                |((bytes[2] & 0xFF) << 8)|(bytes[3] & 0xFF);

                        Log.i(TAG, "received cmd_len:"+String.valueOf(cmd_len));
                        if(cmd_len>0){
                            byte[] ArrayOfByte = new byte[cmd_len];
                            size = input.read(ArrayOfByte, 0, cmd_len);
                            Log.i(TAG, "received data len:" + String.valueOf(size));
                            Parcel parcel = Parcel.obtain();
                            parcel.unmarshall(ArrayOfByte, 0, ArrayOfByte.length);
                            parcel.setDataPosition(0);
                            processRequest(receiver,parcel);
                        }

                    }
                }
            } catch (IOException e) {
                Log.e(getClass().getName(), e.getMessage());
            }
        private void sendResult(LocalSocket paramLocalSocket, Parcel paramParcel) throws IOException{
            byte[] arrayOfByte1 = new byte[4];
            byte[] arrayOfByte2 = paramParcel.marshall();
            Log.i(TAG, "enter sendResult!");
            arrayOfByte1[0] = 0;
            arrayOfByte1[1] = 0;
            arrayOfByte1[2] = (byte)(arrayOfByte2.length >> 8 & 0xFF);
            arrayOfByte1[3] = (byte)(arrayOfByte2.length & 0xFF);

            paramLocalSocket.getOutputStream().write(arrayOfByte1);
            paramLocalSocket.getOutputStream().write(arrayOfByte2);
        }

private void processRequest(LocalSocket paramLocalSocket, Parcel paramParcel)
{
          int cmd = paramParcel.readInt();
          //Log.i(TAG,"parcel:"+String.valueOf(cmd));
          if(cmd>0&&cmd<CMMB_REQUEST_CMD_MAX){
          //String info = "unknown";
          Parcel parcel_info = Parcel.obtain();
          TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
          switch (cmd)
          {
          case CMMB_REQUEST_GET_IMSI:{
              Log.i(TAG, "received CMMB_REQUEST_GET_IMSI command!");
              /*
               * 唯一的用户ID:
               * 例如:IMSI(国际移动用户识别码) for a GSM phone.
               * 需要权限:READ_PHONE_STATE
               */
              String info = tm.getSubscriberId();//String
              if(info!=null) Log.i(TAG, info);
              parcel_info.writeInt(CMMB_REQUEST_GET_IMSI);
              parcel_info.writeString(info);
            }
            break;
....
          try {
             sendResult(paramLocalSocket, parcel_info);
          } catch (IOException e) {
            // TODO Auto-generated catch block
            Log.e(getClass().getName(), e.getMessage());
            e.printStackTrace();
          }

}

以上是服务器端,下面是客户端
#define  SOCKET_NAME_CMMB_SIM_COMMAND   "socket_cmmb_sim_command"
...
    fd = socket_local_client(
                            SOCKET_NAME_CMMB_SIM_COMMAND,
                            ANDROID_SOCKET_NAMESPACE_ABSTRACT,
                            SOCK_STREAM );
    //check open failed
    if (fd < 0)
    {
           LOGE("Failed to open socket: %s\n\r'", SOCKET_NAME_CMMB_SIM_COMMAND);
        goto error;
        }

    //get command data
    p_request.writeInt32 (CMMB_REQUEST_GET_IMSI);
    data = (char *)p_request.data();
    datasize = (int)p_request.dataSize();
    //get command length
    dataLength[0] = dataLength[1] = 0;
    dataLength[2] = (char)((datasize >> 8) & 0xff);
    dataLength[3] = (char)(datasize & 0xff);

    //write command getimsi length
    if(SmsMbbmsSimSocketWrite(fd, dataLength, sizeof(dataLength)) != sizeof(dataLength))
    {
        LOGE("Failed to write cmmand %d 's length to socket: %s!!!!!\n'", CMMB_REQUEST_GET_IMSI, SOCKET_NAME_CMMB_SIM_COMMAND);
        goto error;
    }

    //write command getimsi
    if(SmsMbbmsSimSocketWrite(fd, data, datasize) != datasize)
    {
        LOGE("Failed to write cmmand %d to socket: %s!!!!\n'", CMMB_REQUEST_GET_IMSI, SOCKET_NAME_CMMB_SIM_COMMAND);
        goto error;
    }
    //write end, start read response
    //read head, include length of data, 4 byte
    if(SmsMbbmsSimSocketRead(fd, response_data, 4) != 4)
    {
        LOGE("Failed to read response command %d 's length from socket: %s!!!!!\n'", CMMB_REQUEST_GET_IMSI, SOCKET_NAME_CMMB_SIM_COMMAND);
        goto error;
    }
    //LOGD("response_data of length: %d, %d, %d, %d!!!\n", response_data[0], response_data[1], response_data[2], response_data[3]);
    //calculate length
    response_length = ((response_data[0] & 0xff) << 24)
                    | ((response_data[1] & 0xff) << 16)
                    | ((response_data[2] & 0xff) << 8)
                    | (response_data[3] & 0xff);
    //LOGD("response_length = %d\n", response_length);
    //check length
    if(response_length == 0)
    {
        LOGE("response %d 's length from socket: %s is not right!!!!!\n'", CMMB_REQUEST_GET_IMSI, SOCKET_NAME_CMMB_SIM_COMMAND);
        goto error;
    }
...

这样就是实现了客户端和服务器之间的通信。

相关内容