PC客户端与Android服务端的Socket同步通信(一)

  需求:
        1.一个android端的service后台运行的程序,作为socket的服务器端;用于接收Pc client端发来的命令,来处理数据后,把结果发给PC client
        2.PC端程序,作为socket的客户端,用于给android手机端发操作命令

         难点分析:
        1.手机一定要有adb模式,即插上USB线时马上提示的对话框选adb。好多对手机的操作都可以用adb直接作。
不过,我发现LG GW880就没有,要去下载个
        2.android默认手机端的IP为“127.0.0.1”
        3.要想联通PC与android手机的sokcet,一定要用adb forward 来作下端口转发才能连上socket.

java代码:
  1. Runtime.getRuntime().exec("adb forward tcp:12580 tcp:10086");
  2. Thread.sleep(3000);
复制代码

       4.android端的service程序Install到手机上容易,但是还要有方法来从PC的client端来启动手机上的service ,这个办法可以通过PC端adb命令来发一个Broastcast ,手机端再写个接收BroastcastReceive来接收这个Broastcast,在这个BroastcastReceive来启动service

       pc端命令:

java代码:
  1. Runtime.getRuntime().exec(
  2. "adb shell am broadcast -a NotifyServiceStart");
复制代码

        android端的代码:ServiceBroadcastReceiver.java

java代码:

  1. package eoe.otheri.service;


  2. import android.content.BroadcastReceiver;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.util.Log;


  6. public class ServiceBroadcastReceiver extends BroadcastReceiver {
  7. private static String START_ACTION = "NotifyServiceStart";
  8. private static String STOP_ACTION = "NotifyServiceStop";


  9. @Override
  10. public void onReceive(Context context, Intent intent) {
  11. Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"
  12. + "ServiceBroadcastReceiver onReceive");
  13. String action = intent.getAction();
  14. if (START_ACTION.equalsIgnoreCase(action)) {
  15. context.startService(new Intent(context, androidService.class));
  16. Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"
  17. + "ServiceBroadcastReceiver onReceive start end");
  18. } else if (STOP_ACTION.equalsIgnoreCase(action)) {
  19. context.stopService(new Intent(context, androidService.class));
  20. Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"
  21. + "ServiceBroadcastReceiver onReceive stop end");
  22. }
  23. }


  24. }
复制代码

        5.由于是USB连接,所以socket就可以设计为一但连接就一直联通,即在new socket和开完out,in流后,就用个while(true){}来循环PC端和android端的读和写

        android的代码:

java代码:

  1. public void run() {
  2. Log.d(androidService.TAG, Thread.currentThread().getName() + "---->"
  3. + "a client has connected to server!");
  4. BufferedOutputStream out;
  5. BufferedInputStream in;
  6. try {
  7. /* PC端发来的数据msg */
  8. String currCMD = "";
  9. out = new BufferedOutputStream(client.getOutputStream());
  10. in = new BufferedInputStream(client.getInputStream());
  11. // testSocket();// 测试socket方法
  12. androidService.ioThreadFlag = true;
  13. while (androidService.ioThreadFlag) {
  14. try {
  15. if (!client.isConnected()) {
  16. break;
  17. }


  18. /* 接收PC发来的数据 */
  19. Log.v(androidService.TAG, Thread.currentThread().getName()
  20. + "---->" + "will read......");
  21. /* 读操作命令 */
  22. currCMD = readCMDFromSocket(in);
  23. Log.v(androidService.TAG, Thread.currentThread().getName()
  24. + "---->" + "**currCMD ==== " + currCMD);


  25. /* 根据命令分别处理数据 */
  26. if (currCMD.equals("1")) {
  27. out.write("OK".getBytes());
  28. out.flush();
  29. } else if (currCMD.equals("2")) {
  30. out.write("OK".getBytes());
  31. out.flush();
  32. } else if (currCMD.equals("3")) {
  33. out.write("OK".getBytes());
  34. out.flush();
  35. } else if (currCMD.equals("4")) {


  36. /* 准备接收文件数据 */
  37. try {
  38. out.write("service receive OK".getBytes());
  39. out.flush();
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. }


  43. /* 接收文件数据,4字节文件长度,4字节文件格式,其后是文件数据 */
  44. byte[] filelength = new byte[4];
  45. byte[] fileformat = new byte[4];
  46. byte[] filebytes = null;


  47. /* 从socket流中读取完整文件数据 */
  48. filebytes = receiveFileFromSocket(in, out, filelength,fileformat);
  49. // Log.v(Service139.TAG, "receive data =" + new
  50. // String(filebytes));
  51. try {


  52. /* 生成文件 */
  53. File file = FileHelper.newFile("R0013340.JPG");
  54. FileHelper.writeFile(file, filebytes, 0,
  55. filebytes.length);
  56. } catch (IOException e) {
  57. e.printStackTrace();
  58. }
  59. } else if (currCMD.equals("exit")) {
  60. }
  61. } catch (Exception e) {
  62. // try {
  63. // out.write("error".getBytes("utf-8"));
  64. // out.flush();
  65. // } catch (IOException e1) {
  66. // e1.printStackTrace();
  67. // }
  68. Log.e(androidService.TAG, Thread.currentThread().getName()
  69. + "---->" + "read write error111111");
  70. }
  71. }
  72. out.close();
  73. in.close();
  74. } catch (Exception e) {
  75. Log.e(androidService.TAG, Thread.currentThread().getName()
  76. + "---->" + "read write error222222");
  77. e.printStackTrace();
  78. } finally {
  79. try {
  80. if (client != null) {
  81. Log.v(androidService.TAG, Thread.currentThread().getName()
  82. + "---->" + "client.close()");
  83. client.close();
  84. }
  85. } catch (IOException e) {
  86. Log.e(androidService.TAG, Thread.currentThread().getName()
  87. + "---->" + "read write error333333");
  88. e.printStackTrace();
  89. }
  90. }
复制代码

       6.如果是在PC端和android端的读写操作来while(true){}循环,这样socket流的结尾不好判断,不能用“-1”来判断,因为“-1”是只有在socket关闭时才作为判断结尾。
       7.socket在out.write(bytes);时,要是数据太大时,超过socket的缓存,socket自动分包发送,所以对方就一定要用循环来多次读。最好的办法就是服务器和客户端协议好,比如发文件时,先写过来一个要发送的文件的大小,然后再发送文件;对方用这个大小,来循环读取数据。

       android端接收数据的代码:

java代码:
  1. /**
  2. * 功能:从socket流中读取完整文件数据
  3. *
  4. * InputStream in:socket输入流
  5. *
  6. * byte[] filelength: 流的前4个字节存储要转送的文件的字节数
  7. *
  8. * byte[] fileformat:流的前5-8字节存储要转送的文件的格式(如.apk)
  9. *
  10. * */
  11. public static byte[] receiveFileFromSocket(InputStream in,
  12. OutputStream out, byte[] filelength, byte[] fileformat) {
  13. byte[] filebytes = null;// 文件数据
  14. try {
  15. int filelen = MyUtil.bytesToInt(filelength);// 文件长度从4字节byte[]转成Int
  16. String strtmp = "read file length ok:" + filelen;
  17. out.write(strtmp.getBytes("utf-8"));
  18. out.flush();
  19. filebytes = new byte[filelen];
  20. int pos = 0;
  21. int rcvLen = 0;
  22. while ((rcvLen = in.read(filebytes, pos, filelen - pos)) > 0) {
  23. pos += rcvLen;
  24. }
  25. Log.v(androidService.TAG, Thread.currentThread().getName()
  26. + "---->" + "read file OK:file size=" + filebytes.length);
  27. out.write("read file ok".getBytes("utf-8"));
  28. out.flush();
  29. } catch (Exception e) {
  30. Log.v(androidService.TAG, Thread.currentThread().getName()
  31. + "---->" + "receiveFileFromSocket error");
  32. e.printStackTrace();
  33. }
  34. return filebytes;
  35. }
复制代码

       8.socket的最重要的机制就是读写采用的是阻塞的方式,如果客户端作为命令发起者,服务器端作为接收者的话,只有当客户端client用out.writer()写到输出流里后,即流中有数据service的read才会执行,不然就会一直停在read()那里等数据。

        9.还要让服务器端可以同时连接多个client,即服务器端用new thread()来作数据读取操作。

系列之PC客户端与Android服务端的Socket同步通信(二)的帖子链接 http://www.eoeandroid.com/thread-92828-1-1.html
系列之PC客户端与Android服务端的Socket同步通信(三)的帖子链接 http://www.eoeandroid.com/thread-92834-1-1.html

你可能感兴趣的:(android)