logo资料库

PC客户端与Android服务端的Socket同步通信 实例.pdf

第1页 / 共37页
第2页 / 共37页
第3页 / 共37页
第4页 / 共37页
第5页 / 共37页
第6页 / 共37页
第7页 / 共37页
第8页 / 共37页
资料共37页,剩余部分请下载后查看
PC 客户端与 Android 服务端的 Socket 同步通信(USB) 需求: 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. view plaincopy to clipboardprint? Runtime.getRuntime().exec("adb forward tcp:12580 tcp:10086"); Thread.sleep(3000); Runtime.getRuntime().exec("adb forward tcp:12580 tcp:10086"); Thread.sleep(3000); 4.android 端的 service 程序 Install 到手机上容易,但是还要有方法来从 PC 的 client 端来启动手机上的 service ,这个办法可以通过 PC 端 adb 命令来发一个 Broastcast ,手机 端再写个接收 BroastcastReceive 来接收这个 Broastcast,在这个 BroastcastReceive 来启动 service pc 端命令: view plaincopy to clipboardprint? Runtime.getRuntime().exec( "adb shell am broadcast -a NotifyServiceStart"); Runtime.getRuntime().exec( "adb shell am broadcast -a NotifyServiceStart"); android 端的代码:ServiceBroadcastReceiver.java view plaincopy to clipboardprint? package com.otheri.service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class ServiceBroadcastReceiver extends BroadcastReceiver { private static String START_ACTION = "NotifyServiceStart"; private static String STOP_ACTION = "NotifyServiceStop"; @Override
public void onReceive(Context context, Intent intent) { Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive"); String action = intent.getAction(); if (START_ACTION.equalsIgnoreCase(action)) { context.startService(new Intent(context, androidService.class)); Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive start end"); } else if (STOP_ACTION.equalsIgnoreCase(action)) { context.stopService(new Intent(context, androidService.class)); Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive stop end"); } } } package com.otheri.service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class ServiceBroadcastReceiver extends BroadcastReceiver { private static String START_ACTION = "NotifyServiceStart"; private static String STOP_ACTION = "NotifyServiceStop"; @Override public void onReceive(Context context, Intent intent) { Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive"); String action = intent.getAction(); if (START_ACTION.equalsIgnoreCase(action)) { context.startService(new Intent(context, androidService.class)); Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive start end"); } else if (STOP_ACTION.equalsIgnoreCase(action)) { context.stopService(new Intent(context, androidService.class)); Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive stop end");
} } } 5.由于是 USB 连接,所以 socket 就可以设计为一但连接就一直联通,即在 new socket 和 开完 out,in 流后,就用个 while(true){}来循环 PC 端和 android 端的读和写 android 的代码: view plaincopy to clipboardprint? public void run() { Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "a client has connected to server!"); BufferedOutputStream out; BufferedInputStream in; try { /* PC 端发来的数据 msg */ String currCMD = ""; out = new BufferedOutputStream(client.getOutputStream()); in = new BufferedInputStream(client.getInputStream()); // testSocket();// 测试 socket 方法 androidService.ioThreadFlag = true; while (androidService.ioThreadFlag) { try { if (!client.isConnected()) { break; } /* 接收 PC 发来的数据 */ Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "will read......"); /* 读操作命令 */ currCMD = readCMDFromSocket(in); Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "**currCMD ==== " + currCMD); /* 根据命令分别处理数据 */ if (currCMD.equals("1")) { out.write("OK".getBytes()); out.flush(); } else if (currCMD.equals("2")) { out.write("OK".getBytes());
out.flush(); } else if (currCMD.equals("3")) { out.write("OK".getBytes()); out.flush(); } else if (currCMD.equals("4")) { /* 准备接收文件数据 */ try { out.write("service receive OK".getBytes()); out.flush(); } catch (IOException e) { e.printStackTrace(); } /* 接收文件数据,4 字节文件长度,4 字节文件格式,其后是文 件数据 */ byte[] filelength = new byte[4]; byte[] fileformat = new byte[4]; byte[] filebytes = null; /* 从 socket 流中读取完整文件数据 */ filebytes = receiveFileFromSocket(in, out, filelength, fileformat); // Log.v(Service139.TAG, "receive data =" + new // String(filebytes)); try { /* 生成文件 */ File file = FileHelper.newFile("R0013340.JPG"); FileHelper.writeFile(file, filebytes, 0, filebytes.length); } catch (IOException e) { e.printStackTrace(); } } else if (currCMD.equals("exit")) { } } catch (Exception e) { // try { // out.write("error".getBytes("utf-8")); // out.flush(); // } catch (IOException e1) { // e1.printStackTrace(); // } Log.e(androidService.TAG, Thread.currentThread().getName()
+ "---->" + "read write error111111"); } } out.close(); in.close(); } catch (Exception e) { Log.e(androidService.TAG, Thread.currentThread().getName() + "---->" + "read write error222222"); e.printStackTrace(); } finally { try { if (client != null) { Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "client.close()"); client.close(); } } catch (IOException e) { Log.e(androidService.TAG, Thread.currentThread().getName() + "---->" + "read write error333333"); e.printStackTrace(); } } public void run() { Log.d(androidService.TAG, Thread.currentThread().getName() + "---->" + "a client has connected to server!"); BufferedOutputStream out; BufferedInputStream in; try { /* PC 端发来的数据 msg */ String currCMD = ""; out = new BufferedOutputStream(client.getOutputStream()); in = new BufferedInputStream(client.getInputStream()); // testSocket();// 测试 socket 方法 androidService.ioThreadFlag = true; while (androidService.ioThreadFlag) { try { if (!client.isConnected()) { break; } /* 接收 PC 发来的数据 */ Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "will read......"); /* 读操作命令 */
件数据 */ currCMD = readCMDFromSocket(in); Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "**currCMD ==== " + currCMD); /* 根据命令分别处理数据 */ if (currCMD.equals("1")) { out.write("OK".getBytes()); out.flush(); } else if (currCMD.equals("2")) { out.write("OK".getBytes()); out.flush(); } else if (currCMD.equals("3")) { out.write("OK".getBytes()); out.flush(); } else if (currCMD.equals("4")) { /* 准备接收文件数据 */ try { out.write("service receive OK".getBytes()); out.flush(); } catch (IOException e) { e.printStackTrace(); } /* 接收文件数据,4 字节文件长度,4 字节文件格式,其后是文 byte[] filelength = new byte[4]; byte[] fileformat = new byte[4]; byte[] filebytes = null; /* 从 socket 流中读取完整文件数据 */ filebytes = receiveFileFromSocket(in, out, filelength, fileformat); // Log.v(Service139.TAG, "receive data =" + new // String(filebytes)); try { /* 生成文件 */ File file = FileHelper.newFile("R0013340.JPG"); FileHelper.writeFile(file, filebytes, 0, filebytes.length); } catch (IOException e) { e.printStackTrace(); } } else if (currCMD.equals("exit")) {
} } catch (Exception e) { // try { // out.write("error".getBytes("utf-8")); // out.flush(); // } catch (IOException e1) { // e1.printStackTrace(); // } Log.e(androidService.TAG, Thread.currentThread().getName() + "---->" + "read write error111111"); } } out.close(); in.close(); } catch (Exception e) { Log.e(androidService.TAG, Thread.currentThread().getName() + "---->" + "read write error222222"); e.printStackTrace(); } finally { try { if (client != null) { Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "client.close()"); client.close(); } } catch (IOException e) { Log.e(androidService.TAG, Thread.currentThread().getName() + "---->" + "read write error333333"); e.printStackTrace(); } } 6.如果是在 PC 端和 android 端的读写操作来 while(true){}循环,这样 socket 流的结尾不好 判断,不能用“-1”来判断,因为“-1”是只有在 socket 关闭时才作为判断结尾。 7.socket 在 out.write(bytes);时,要是数据太大时,超过 socket 的缓存,socket 自动分包发 送,所以对方就一定要用循环来多次读。最好的办法就是服务器和客户端协议好,比如发文 件时,先写过来一个要发送的文件的大小,然后再发送文件;对方用这个大小,来循环读取 数据。 android 端接收数据的代码: view plaincopy to clipboardprint?
/** * 功能:从 socket 流中读取完整文件数据 * * InputStream in:socket 输入流 * * byte[] filelength: 流的前 4 个字节存储要转送的文件的字节数 * * byte[] fileformat:流的前 5-8 字节存储要转送的文件的格式(如.apk) * * */ public static byte[] receiveFileFromSocket(InputStream in, OutputStream out, byte[] filelength, byte[] fileformat) { byte[] filebytes = null;// 文件数据 try { int filelen = MyUtil.bytesToInt(filelength);// 文件长度从 4 字节 byte[]转成 Int String strtmp = "read file length ok:" + filelen; out.write(strtmp.getBytes("utf-8")); out.flush(); filebytes = new byte[filelen]; int pos = 0; int rcvLen = 0; while ((rcvLen = in.read(filebytes, pos, filelen - pos)) > 0) { pos += rcvLen; } Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "read file OK:file size=" + filebytes.length); out.write("read file ok".getBytes("utf-8")); out.flush(); } catch (Exception e) { Log.v(androidService.TAG, Thread.currentThread().getName() + "---->" + "receiveFileFromSocket error"); e.printStackTrace(); } return filebytes; } /** * 功能:从 socket 流中读取完整文件数据 * * InputStream in:socket 输入流 * * byte[] filelength: 流的前 4 个字节存储要转送的文件的字节数 * * byte[] fileformat:流的前 5-8 字节存储要转送的文件的格式(如.apk)
分享到:
收藏