IPC通讯

作者: 冬冬269 | 来源:发表于2018-08-28 16:17 被阅读0次

    IPC进程间通讯,对象需要被序列化。因为是通过二进制序列的形式来传递,内存中的对象需要通过序列化转成字节序列。

    Serializable

    Parcelable

    都可以进行序列化。serializable序列过程中要进行大量io操作,耗内存,效率低。
    parcelable,android专门用来做序列化的,内存消耗低,效率高。如果是进程间通讯,在内存中操作用parcelable。如果要保存到硬盘或网络传输用serializable,更稳定。

    所有在IBunder中传输的接口,都要继承Iinterface接口。

    跨进程通讯的方式

    Bundle

    写入intent中,基本数据类型,或者实现了serializable和parcelable接口的对象。intent最多不能超过500kb哦。

    本地文件

    通过本地共享的文件来实现通讯,高并发时,可能拿到的不是最新的数据,另外sp存储底层是xml,以键值对的形式存储的,应用中有对sp的内存缓存机制,当高并发时,可能造成数据丢失,所以不能用。

    Messenger

    客户端进程 绑定服务端的service,服务端返回一个IBinder对象,通过Messenger创建,Messenger.getBinder(),客户端绑定后返回一个IBinder对象,通过new Messenger(IBINDER) 创建出这个Messenger,就可以通过Message发送和接收数据了,回传信息是客户端创建一个Messenger对象,发送消息时通过message的replyTo参数,把这个Messenger传给服务端,服务端就可以回传数据。请看代码

    public class MyServiceForMessenger extends Service {
    
        @Override
        public void onCreate() {
            super.onCreate();
            serviceList = new ArrayList<>();
            Log.i("dongdong","创建了");
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.i("dongdong","绑定了");
            return stub.getBinder();
        }
    
        private List<Book> serviceList;
      public class MyMessenger extends Handler{
          @Override
          public void handleMessage(Message msg) {
              switch(msg.what){
    
                  case Constant.MSG_FROM_CLIENT:
                      String msg1 = msg.getData().getString("msg");
                      Log.i("dongdong",msg1);
                      Messenger replyTo = msg.replyTo;
                      Message obtain = Message.obtain(null, Constant.MSG_FROM_CLIENT);
                      Bundle bundle = new Bundle();
                      bundle.putString("delay","收到了,但是回复你好麻烦");
                      obtain.setData(bundle);
                      try {
                          replyTo.send(obtain);
                      } catch (RemoteException e) {
                          e.printStackTrace();
                      }
                      break;
    
                  default:
                      super.handleMessage(msg);
              }
    
          }
      }
        Messenger stub = new Messenger(new MyMessenger());
    }
    
    public class DemoBactivity extends Activity {
    
        private Messenger messenger;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
    
    
            setContentView(R.layout.activity_demo_a);
            Button viewById = (Button) findViewById(R.id.btn_a);
            Button viewById2 = (Button) findViewById(R.id.btn_getlist);
            Button viewById3 = (Button) findViewById(R.id.btn_addlist);
            Button viewById4 = (Button) findViewById(R.id.btn_startB);
    
            viewById2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Message obtain = Message.obtain(null, Constant.MSG_FROM_CLIENT);
                    Bundle bundle = new Bundle();
                    bundle.putString("msg","这里是dongdongdemo发送的信息,服务端收到了吗");
                    obtain.setData(bundle);
                    obtain.replyTo = Bmessenger;
                    try{
                        messenger.send(obtain);
                    }catch(Exception t){
    
                    }
    
                }
            });
            final ServiceConnection serviceConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                    messenger = new Messenger(iBinder);
    
                }
    
                @Override
                public void onServiceDisconnected(ComponentName componentName) {
    
                }
            };
            viewById.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                  //  startActivity(new Intent(DemoBactivity.this,DemoCactivity.class));
    
                    bindService(new Intent(DemoBactivity.this,MyServiceForMessenger.class),serviceConnection, Service.BIND_AUTO_CREATE);
                }
            });
        }
    
        private Messenger Bmessenger = new Messenger(new MyMessendClientHandler());
        class MyMessendClientHandler extends Handler{
    
            @Override
            public void handleMessage(Message msg) {
    
    
                switch (msg.what){
                    case Constant.MSG_FROM_CLIENT:
    
                        String delay = msg.getData().getString("delay");
                        Log.i("dongdong",delay);
    
                        break;
                        default:
                            super.handleMessage(msg);
                }
            }
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.i("dongdong","BBB启动了一次start");
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.i("dongdong","BBB启动了一次restart");
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            Log.i("dongdong","BBB启动了一次onNewIntent");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.i("dongdong","BBB启动了一次onResume");
        }
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            Log.i("dongdong","BBB启动了一次onSaveInstanceState");
        }
    
        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);
            Log.i("dongdong","BBB启动了一次onRestoreInstanceState");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.i("dongdong","BBB启动了一次onPause");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.i("dongdong","BBB启动了一次onStop");
        }
    
    }
    

    message工作原理。


    image.png

    AIDL

    这种是最常用的了。messenger为什么不常见,从实现方式可以看出,是串行。当高并发时,由handler处理。全部在handler的messagequeue中一件一件处理。如果有大量并发请求,就不行了。同时有时我们需要跨进程调用服务端的方法,Messenger页不行,但是AIDL行。

    服务端

    服务端需要创建一个service来监听客户端的请求。在服务端中写aidl,在aidl把暴露给客户端的接口声明,然后在service中实现这个接口。

    客户端

    绑定服务端的service,把返回的binder转成aidl接口所属的类型,然后通过这个接口就可以去调用了。

    客户端调用服务端,服务端也可以回调客户端。

    aidl具体实现 创建aidl接口,里面声明方法,如果入参有自定义的对象,要手动导入这个对象,并且对象要继承parcelable,并且在aidl文件夹中要声明出来。入参型参数前面加in 出参型out 综合性inout

    package com.spu.dong.spu.activity.aidl;
    
    // Declare any non-default types here with import statements
    
    parcelable Book;
    
    // IBookManager.aidl
    package com.spu.dong.spu.activity.aidl;
    import com.spu.dong.spu.activity.aidl.Book;
    import com.spu.dong.spu.activity.aidl.AddBookListener;
    // Declare any non-default types here with import statements
    
    interface IBookManager {
    
        List<Book> getBookList();
        void addBook(in Book book);
        void registAddBookListener(in AddBookListener addBookListener);
        void unRegistAddBookListener(in AddBookListener addBookListener);
    }
    
    package com.spu.dong.spu.activity.aidl;
    import com.spu.dong.spu.activity.aidl.Book;
    // Declare any non-default types here with import statements
    
    interface AddBookListener {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
       void addOneBook(in Book book);
    }
    

    service中的实现,用到了RemoteCallBackList,这个不是list,底层是一个Map,把binde做key,把Callback<listener,cookies>做value,保存起来。有时的需求是服务端回调客户端,客户端有绑定和解绑回调接口的功能。客户端创建回调接口的实例a,传给服务端后,服务端会产生一个新的接口实例b,因为是不同线程的,不在同一个内存中。那么当客户端需要解绑时,把自己创建的回调接口a传过去时,服务端这是又产生了一个接口实例c,b和c不对应,所以没办法解绑。但是他们的底层binder是同一个,所以这个remotecallbacklist会遍历,根据listener.asbinder()的key,找到这个listener,然后去解绑。就可以了。并且remotecallbacklist会自动删除listener,在连接这个listener的客户端销毁时。遍历remotecallbacklist是要注意,调用.beginBroadcast时要配对使用.finishBroadcast(),哪怕你只是获取这个对象的内容多少。下面贴一下完整代码

    public class MyService extends Service {
    
        @Override
        public void onCreate() {
            super.onCreate();
            serviceList = new CopyOnWriteArrayList<>();
            addBookList = new RemoteCallbackList<>();
            Log.i("dongdong","创建了");
        }
    
        private boolean serviceFlage = false;
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.i("dongdong","绑定了");
            serviceFlage = true;
            new Thread(new ServiceWork()).start();
            return stub;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            serviceFlage = false;
            return super.onUnbind(intent);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            serviceFlage = false;
        }
    
        private CopyOnWriteArrayList<Book> serviceList;
        private RemoteCallbackList<AddBookListener> addBookList;
        IBookManager.Stub stub = new IBookManager.Stub(){
    
            @Override
            public List<Book> getBookList() throws RemoteException {
                return serviceList;
            }
    
            @Override
            public void addBook(Book book) throws RemoteException {
                serviceList.add(book);
            }
    
            @Override
            public void registAddBookListener(AddBookListener addBookListener) throws RemoteException {
                //有人注册了这个服务,就在服务端保存一下这个listener 添加新书的时候。调用list中的所有addBookListener
                addBookList.register(addBookListener);
            }
    
            @Override
            public void unRegistAddBookListener(AddBookListener addBookListener) throws RemoteException {
                addBookList.unregister(addBookListener);
            }
        };
    
        private class ServiceWork implements Runnable{
    
            @Override
            public void run() {
    
                try {
                    //绑定了
                    while (serviceFlage)  {
    
    
                    Thread.sleep(5*1000);
                    Book book = new Book(serviceList.size() + 1, "book#bookid" + (serviceList.size() + 1));
                    //加本书
                    serviceList.add(book);
                    //监听的方法 都调用一下
                        int N = addBookList.beginBroadcast();
                        for (int i = 0;i<N;i++ ){
                            AddBookListener broadcastItem = addBookList.getBroadcastItem(i);
                            broadcastItem.addOneBook(book);
                        }
                        addBookList.finishBroadcast();//finishBroadCast 和 beginBroadcase 配对使用
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
        }
    }
    
    
    public class DemoAactivity extends Activity {
    
        private IBookManager iBookManager;
        AddBookListener.Stub stub;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
    
            setContentView(R.layout.activity_demo_a);
            Button viewById = (Button) findViewById(R.id.btn_a);
            Button viewById2 = (Button) findViewById(R.id.btn_getlist);
            Button viewById3 = (Button) findViewById(R.id.btn_addlist);
            Button viewById4 = (Button) findViewById(R.id.btn_startB);
    
            stub = new AddBookListener.Stub() {
                @Override
                public void addOneBook(Book book) throws RemoteException {
                    //应该发送给子线程去处理。这里简单点。
                    Log.i("dongdong","我看下是什么书"+book.bookId+book.bookName);
                }
            };
            viewById4.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //startActivity(new Intent(DemoAactivity.this,DemoBactivity.class));
                    //解除绑定
                    try {
                        iBookManager.unRegistAddBookListener(stub);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            });
            viewById2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    try{
                        List<Book> bookList = iBookManager.getBookList();
                        Log.i("dongodng",bookList.size()+"");
                    }catch(Exception t ){
                        Log.i("dongdong","ipc失败");
                    }
    
                }
            });
            viewById3.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    try{
                         iBookManager.addBook(new Book(11,"好书"));
                    }catch(Exception t ){
                        Log.i("dongdong","ipc失败");
                    }
    
                }
            });
            final ServiceConnection serviceConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    
                    iBookManager = IBookManager.Stub.asInterface(iBinder);
    
                    try {
                        iBookManager.registAddBookListener(stub);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
    
                @Override
                public void onServiceDisconnected(ComponentName componentName) {
    
                }
            };
            viewById.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //startActivity(new Intent(DemoAactivity.this,DemoBactivity.class));
    
                    //进程间通信
                    Intent intent = new Intent(DemoAactivity.this,MyService.class);
                    boolean b = bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
    
                    //绑定服务后。注册一下监听
    
    
                }
            });
        }
    
    
        @Override
        protected void onStart() {
            super.onStart();
        }
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            Log.i("dongdong","AAA启动了一次saveinstance");
        }
    
    
        @Override
        protected void onResume() {
            super.onResume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
        }
    
        @Override
        protected void onStop() {
            super.onStop();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
        }
    }
    
    

    实际上,根据binder机制我们知道。服务端调用客户端的回调方法时,这个方法是运行在客户端的binder线程池中执行的,为了ui操作,我们需要一个handler把他切换到主线程中去操作。我对这句话的理解,因为客户端发起远程请求时,线程会挂起,直至服务端返回数据,所以是耗时的,所以尽量创建一个子线程去发起远程请求,那么回调也是在子线程中,如果要回到主线程操作ui,就需要一个handler。另外binder中的方法运行在服务端的线程池中,所以binder的方法都应采用同步的方式去实现。

    过程中如果binder断裂,binder死亡了怎么办,通过linktoDeath()设置死亡代理,binder死亡时,会回调代理中的方法,我们可以从新创建连接。
    首先创建deathRecipient, 这是个接口,里面有一个binderdied,当binder死亡,系统会回调binderdied,我们在方法里移出之前绑定的binder代理,重新绑定。

     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            @Override
            public void binderDied() {
                if (mBookManager == null)
                    return;
                mBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
                mBookManager  = null;
                // TODO: 重新绑定远程service
            }
        };
    
    service死亡。binder断裂 怎么办?
    1.给binder设置死亡代理,deathRecipient。
    mService = IMessageBoxManager.Stub.asInterface(binder);
    binder.linkToDeath(mDeathRecipient, 0);
    

    2.断裂会回调onServiceDisConnector的方法,方法中做处理。

    3.安全性,我们的service不是谁想调谁就调的,那么我们在onBind 或者onTransact中做判断,一个是自定义权限,一个是或者client的pid uid 来做一些判断。

    ContentProvider

    1.以表格的形式来组织数据,可以包含多张表,对于每张表格来说,有行和列的层次性,和数据库类似。底层数据看起来很像一个sqlite数据库,但是contentprovider对底层数据存储方式没有任何要求,可以是数据库,可以是文件,甚至一个内存中的对象进行数据存储。
    2.例子。继承contentpervider,实现其中方法,使用UriMatcher,addUri将uri和uricode关联起来,我们就可以根据uri拿到code,match(uri)就知道外界对哪个表进行操作,可对不同的表进行操作,authorities是contentprovider的唯一标识,很重要。实现SqliteOpenHelper,在onCreate方法中创建XXX.db。getContentResolver来操作数据库,ContentResolver代理的是ContentProvider。增删改查都运行在binder的线程池中,ContentResolver可以注册观察者registerContentObserver。

    Socket

    分为流式套接字和数据报套接字两种,对应网络的传输控制层的两种协议,TCP协议和UDP协议。

    TCP和UDP的区别:

    1.TCP是面向连接的,UDP是不需要连接的。
    2.TCP可以提供的稳定的双向通信,UDP不稳定的单向通信(可以做双向,但还是不稳定)。
    3.TCP需要三次握手建立连接,并具有超时重传机制,稳定性高,占用资源多,UDP不需要建立连接,稳定性低,占用资源少。从性能上看,UDP效率高。UDP没有阻塞控制。

    TCP三次握手

    ACK 应答的,SYN同步的。

    1.A向B发送数据包SYN = 1,seq number随机(A知道)。状态:CLOSE>>SYN_SENT。
    2.B接收到数据包,SYN= 1 标识A要建立连接,B向A发送数据包SYN = 1,ACK = 1,ack = seq+1,seq number。状态CLOSE>>LISTEN>>>>SYN_RECV。
    3.A接到数据包,SYN = 1 B可以建立连接,ack判断是自己发出去的数据包得到的返回,A向B发送数据包ACK = 1,ack = B的seq +1,seq = A的seq+1。状态:SYN_SENT>>ESTABLISHED。
    4.B拿到数据包,SYN = 1 ,ack 正确。SYN_SENT>>>ESTABLISHED。

    image.png

    TCP四次挥手

    任何一方都可以发起关闭。

    1.A向B发送,FIN = 1,seq = n。状态 ESTABLISHED>>FIN_WAIT_1。
    2.B接到数据包,FIN = 1,哦是要关闭。可我还没传输完。B发送数据包。ACK = 1,ack = n=1,seq = v。状态:ESTABLISHED>>>CLOSE_WAIT。
    3.B我传输完了,B发送数据包,FIN = 1,ACK = 1,ack = n+1,seq = m。B:CLOSE_WAIT>>>LASK_TASK。
    4.A接到数据包,FIN =1,ack对的,哦可以关了,A发送数据包,ACK = 1,seq = n+1,ack = m+1。状态:接到包A:FIN_WAIT_1>>>FIN_WAIT_2。发送包A:FIN_WAIT_2>>>TIME_WAIT。2sml后关闭TIME_WAIT>>>CLOSE。
    5.B接到数据包,ack 对的,seq对的。LAST_TASK>>CLOSE。

    为什么三次握手?

    信道不稳定,数据要稳定,三次最少,为什么不是两次,A要确认一次,防止网络延迟,使B一厢情愿建立连接而A不知道。

    为什么四次挥手?

    第一次客户端要断开连接,服务端并不一定已经发送完数据,不能同步。所以要发送客户端两次,一次我知道了,一次我发完了。

    Binder连接池 一个servicer 管理多个AIDL
    创建对象

    // aa.aidl
    package com.xdw.myapplication.demo;
    
    // Declare any non-default types here with import statements
    
    parcelable Book;
    

    创建两个aidl

    // BookDelete.aidl
    package com.xdw.myapplication.demo;
    import com.xdw.myapplication.demo.Book;
    // Declare any non-default types here with import statements
    
    interface BookDelete {
    
      int deleteBook(in Book book);
    }
    
    // BookMagager.aidl
    package com.xdw.myapplication.demo;
    import com.xdw.myapplication.demo.Book;
    // Declare any non-default types here with import statements
    
    interface BookMagager {
    
      String addBook(in Book book);
    
    
    }
    
    

    创建aidl管理

    // QueryManager.aidl
    package com.xdw.myapplication.demo;
    
    // Declare any non-default types here with import statements
    
    interface QueryManager {
       IBinder getBinder(in int code);
    }
    
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class Book implements Parcelable{
    
        public int code;
        public String name;
    
        public Book(int code,String name){
    
            this.code = code;
            this.name = name;
        }
    
        protected Book(Parcel in) {
            code = in.readInt();
            name = in.readString();
        }
    
        public static final Creator<Book> CREATOR = new Creator<Book>() {
            @Override
            public Book createFromParcel(Parcel in) {
                return new Book(in);
            }
    
            @Override
            public Book[] newArray(int size) {
                return new Book[size];
            }
        };
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(code);
            dest.writeString(name);
        }
    }
    
    image.png
    public void onViewClicked(View view) {
            switch (view.getId()) {
                case R.id.btn_connect:
                    Intent intent = new Intent();
                    intent.setComponent(new ComponentName("com.xdw.myapplication","com.xdw.myapplication.service.ServiceDemo"));
                    bindService(intent,new myConnection(), Service.BIND_AUTO_CREATE);
                    break;
                case R.id.btn_delete:
    
                    try {
                        IBinder binder = queryManager.getBinder(0);
                        BookDelete bookDelete = BookDelete.Stub.asInterface(binder);
                        int num = bookDelete.deleteBook(new Book(0, "删除的书"));
                        Toast.makeText(ClientActivity.this,num+"",Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                case R.id.btn_add:
    
                    try{
                        IBinder binder = queryManager.getBinder(1);
                        BookMagager bookMagager = BookMagager.Stub.asInterface(binder);
                        String bookName = bookMagager.addBook(new Book(11111, "添加的书"));
                        Toast.makeText(ClientActivity.this,bookName,Toast.LENGTH_SHORT).show();
                    }catch(Exception t){
    
                    }
                    break;
            }
        }
    

    service

    image.png

    相关文章

      网友评论

          本文标题:IPC通讯

          本文链接:https://www.haomeiwen.com/subject/xzmjbftx.html