我们都知道intent是Android各组件之间通信的核心。对于简单的的进程内或进程间通信,intent基本能够满足了。但是一些稍微复杂些的交互(如一些随时需要的控制请求)等,仅仅依靠intent这种消息机制实现便显得力不从心了。关于Android进程间的通信,大家普遍用的还是AIDL,但它只适用于 Activity与Service之间的通信,不免有一定的限制。而我这次主要介绍的是LocalSocket。
之前关于套接字的操作都是在C上使用的,虽然java封装了很多细节,但用起来不免有些不习惯。C虽然繁琐却使得开发者更为了解其具体细节。而本文也旨在记录自己毕设中用到技术或碰到的问题,以java角度出发。先看看TCP socket通信的模型,LocalSocket也一样只不过是没有跨越网络边界:
认识几个常用的函数:
客户端:
LocalSocket客户端使用,创建套接字
LocalSocketAddress 套接字地址,其实就是文件描述符(主要是服务器的地址,当然也可以客户端自个绑定地址)
setSoTimeout设置超时
connect客户端主动向服务端请求连接
服务端:
LocalServerSocket服务端使用,创建套接字同时指定文件描述符
accept等待客户端连接(阻塞)
共同:
getInputStream获取套接字输入流
getOutputStream获取套接字输出流
close关闭套接字,客户服务都需要
关于套接字的通信直接就是对java输入输出流的操作了,但是有一点很重要:对于套接字获取的各种输入或者输出流,如果调用close函数关闭了对应的流,那么套接字也会自动关闭了,再次对其获取输入输出流的时候会提示 socket not creat 。这点不同于C下socket的 shutdown函数,我也因为这折腾了很久。
下面不多说上代码,我对在客户端对其做了小小的封装:
1. class ClientConnect {
2. private static final String TAG = "ClientConnect";
3. private static final String name = "com.repackaging.localsocket";
4. private LocalSocket Client = null;
5. private PrintWriter os = null;
6. private BufferedReader is = null;
7. private int timeout = 30000;
8.
9. public void connect(){
10. try {
11. new LocalSocket();
12. new LocalSocketAddress(name));
13. Client.setSoTimeout(timeout);
14. catch (IOException e) {
15. e.printStackTrace();
16. }
17. }
18.
19. public void send(String[] data) {
20. try {
21. new PrintWriter(Client.getOutputStream());
22. for(int i = 0 ; i < data.length ; i ++){
23. 0]);
24. }
25. os.println(FLAG);
26. os.flush();
27. "send");
28. catch (IOException e) {
29. e.printStackTrace();
30. }
31. }
32.
33. public String recv() {
34. "recv");
35. null;
36. try {
37. new BufferedReader(new InputStreamReader(Client.getInputStream()));
38. result = is.readLine();
39. Log.d(TAG, result);
40. catch (IOException e) {
41. e.printStackTrace();
42. finally {
43. }
44. return result;
45. }
46.
47. public void close() {
48. try {
49. is.close();
50. os.close();
51. Client.close();
52. catch (IOException e) {
53. e.printStackTrace();
54. }
55. }
56. }
调用代码:
1. ClientConnect client = new ClientConnect();
2. client.connect();
3. client.send(data);
4. result = client.recv();
5. client.close();
由于是在Android代码上使用,为了防止ANR,对于服务端,肯定是放到线程中去的。对于阻塞模式的客户端(recv等函数),也必须放在线程中。
服务端线程:
1. class ServerThread implements Runnable {
2.
3. @Override
4. public void run() {
5. null;
6. null;
7. null;
8. null;
9. null;
10. try {
11. new LocalServerSocket("com.repackaging.localsocket");
12. while (true) {
13. connect = server.accept();
14. Credentials cre = connect.getPeerCredentials();
15. "accept socket uid:"+cre.getUid());
16. new BufferedReader(new InputStreamReader
17. (connect.getInputStream()));
18. while((readString=mBufferedReader.readLine())!=null){
19. if(readString.equals("finish")) break;
20. Log.d(TAG,readString);
21. }
22. new PrintWriter(connect.getOutputStream());
23. "allow");
24. os.flush();
25. "send allow");
26. }
27. catch (IOException e) {
28. e.printStackTrace();
29. }
30. finally{
31. try {
32. mBufferedReader.close();
33. os.close();
34. connect.close();
35. server.close();
36. catch (IOException e) {
37. e.printStackTrace();
38. }
39. }
40. }
41.
42. }
以上就是简单的LocalSocket模型。在处理交互方面还是很方便的,尽量都放到线程中去执行。