IPC通讯

2018-08-28  本文已影响0人  冬冬269

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
上一篇下一篇

猜你喜欢

热点阅读