找到的最好的博客 https://blog.csdn.net/jakemiao/article/details/17270785?locationNum=7&fps=1 下面是demo: https://github.com/yunzheyue/usbCommunication 使用时,将app安装到手机上,然后运行testPcClient类的main方法。 这时候在main()方法中,会运行adb命令,发送广播启动app中的服务,并模拟在电脑端进行发送数据。 app相当于一个服务器,这时候,接到广播后就会启动服务,然后通过socket通讯获取数据。 ———————————————— 版权声明:本文为CSDN博主「yuezheyue123」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/yuezheyue123/article/details/83375235 最近项目中有一个功能需要用到Android与PC端同步数据。查阅了相关资料后,采取了一种建立在adb基础之上的Usb通信方式:由于adb可以将Usb模拟为网卡,所以可以利用socket通信的方式实现Android与PC机的通信,以完成同步功能。 一、Android与PC通信的实现 在《PC客户端与Android服务端的Sockect同步通信》一文详细介绍了建立在adb基础之上的usb(socket)实现的具体方法。大体上的思路如下: ①Android作为server,侦探socket连接请求;添加一个服务类来实现侦听功能。 ②PC端作为Client,请求建立socket连接。 ③Android端添加一个广播接收类,接受PC端通过Adb发送的广播消息,以启动或者停止①中添加的服务。 ④PC端通过Adb发送广播消息通知Android端启动或停止用来侦听socket连接的服务。 1、PC端通过Adb发送广播,使Android端开启侦听Socket的服务,然后再请求连接。代码如下: string strCmd = "adb shell am broadcast -a NotifyServiceStop"; Execute(strCmd, wait_ms); strCmd = "adb forward tcp:12580 tcp:10086"; Execute(strCmd, wait_ms); strCmd = "adb shell am broadcast -a NotifyServiceStart"; Execute(strCmd, wait_ms); IPAddress ipaddress = IPAddress.Parse("127.0.0.1"); tcpClient.Connect(ipaddress, 12580); NetworkStream networkkStream = tcpClient.GetStream(); networkkStream.ReadTimeout = timeOut; networkkStream.WriteTimeout = timeOut; reader = new BinaryReader(networkkStream); writer = new BinaryWriter(networkkStream);
其中,Execute()函数用来执行cmd命令,
private string Execute(string command, int seconds) string output = ""; //输出字符串 if (command != null && !command.Equals("")) Process process = new Process();//创建进程对象 ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = "cmd.exe";//设定需要执行的命令 startInfo.Arguments = "/C " + command;//“/C”表示执行完命令后马上退出 startInfo.UseShellExecute = false;//不使用系统外壳程序启动 startInfo.RedirectStandardInput = false;//不重定向输入 startInfo.RedirectStandardOutput = true; //重定向输出 startInfo.CreateNoWindow = true;//不创建窗口 process.StartInfo = startInfo; if (process.Start())//开始进程 process.WaitForExit();//这里无限等待进程结束 process.WaitForExit(seconds); //等待进程结束,等待时间为指定的毫秒 output = process.StandardOutput.ReadToEnd();//读取进程的输出
2、在Android端,首先需要添加一个广播接收类来处理广播消息,当接受到广播消息是“启动”消息时启动侦听服务,“关闭“消息时停止服务:public class ServiceBroadcastReceiver extends BroadcastReceiver { private static String START_ACTION = "NotifyServiceStart"; private static String STOP_ACTION = "NotifyServiceStop"; public void onReceive(Context context, Intent intent) { Log.d(ConnectService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive"); String action = intent.getAction(); if (START_ACTION.equalsIgnoreCase(action)) { context.startService(new Intent(context, ConnectService.class)); Log.d(ConnectService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive start end"); } else if (STOP_ACTION.equalsIgnoreCase(action)) { context.stopService(new Intent(context, ConnectService.class)); Log.d(ConnectService.TAG, Thread.currentThread().getName() + "---->" + "ServiceBroadcastReceiver onReceive stop end");
然后,添加一个服务类,用来侦听客户端的连接请求:
public class ConnectService extends Service{ public static final String TAG = "chl"; public static Boolean mainThreadFlag = true; public static Boolean ioThreadFlag = true; ServerSocket serverSocket = null; final int SERVER_PORT = 10086; public IBinder onBind(Intent intent) Log.d(TAG, "androidService--->onCreate()"); public int onStartCommand(Intent intent, int flags, int startId) serverSocket = new ServerSocket(SERVER_PORT); Socket socket = serverSocket.accept(); new Thread(new ThreadReadWriterIOSocket(this, socket)).start(); if (serverSocket != null)
还需要添加一个线程类,来处理客户端的连接请求。建立一个连接后,启动一个此线程来完成与客户端的通信。在这里可以定义与实际需求相应的通信协议。public class ThreadReadWriterIOSocket implements Runnable{ private PigProtocol pigProtocol; public ThreadReadWriterIOSocket(Context context, Socket client) pigProtocol = new PigProtocol(); BufferedOutputStream out; out = new BufferedOutputStream(client.getOutputStream()); in = new BufferedInputStream(client.getInputStream()); ConnectService.ioThreadFlag = true; while (ConnectService.ioThreadFlag){ if(!client.isConnected()){ header = pigProtocol.readHeaderFromSocket(in); // TODO: handle exception // TODO: handle exception
最后,还需要修改程序清单manifest.xml,加入代码,使程序能够接收到广播消息,并且指定处理消息的类。注意,在指定接收广播消息类、服务类时,一定要指出完整名称,如com.example.connect.ServiceBroadcastReceiver。<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <receiver android:name=".ServiceBroadcastReceiver"> <action android:name="NotifyServiceStart"/> <action android:name="NotifyServiceStop" /> android:name=".ConnectService">
二、Android与PC端传通过socket传递对象 有了上面的工作,就可以实现Android与PC端通过socket(usb)传递简单的字符串了。但是在实际使用过程中,我们更多的往往是传递对象而不是简单的字符串。最简单的方法是定义相应的协议,在发送端将对象拼接为字符串,然后在接收将接收到的字符串端拆分组合为对象。但是这样实现起来不是很方便,《C#(服务器)与Java(客户端)通过Socket传递对象》一文介绍了利用Json来传递对象的方法。利用文中介绍的方法可以很方便的实现对象传递。《DataContractJsonSerializer类操作json类型数据》一文介绍了C#端json类型数据的具体使用方法。 我们知道,C#和Java都是完全面向对象的语言,它们都提供了List<T>泛型,所以我们可以利用List<T>泛型实现一次发送一组对象。 1、在PC端,首先需要完成Json类型与List<T>类型的相互转换。转换得到的Json字符串通过socket发送给Android端,或者读取得到的Json字符串转换为相应的泛型对象,这样就实现了一次发送一组对象的功能。下面是Json字符串与泛型对象相互转换的实现过程,实现了Json类型字符串与C#对象(包括List<T>类型的对象)的相互转换。 public static string Obj2Json<T>(T data) DataContractJsonSerializer json = new DataContractJsonSerializer(data.GetType()); using (MemoryStream ms = new MemoryStream()) json.WriteObject(ms, data); return Encoding.UTF8.GetString(ms.ToArray()); catch (System.Exception ex) public static object Json2Obj(string strJson, Type t) DataContractJsonSerializer json = new DataContractJsonSerializer(t); using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(strJson))) return json.ReadObject(ms); catch (System.Exception ex)
2、Android端Json与对象的相互转换通过开源项目google-gson实现。下载包后在项目中导入,并且添加引用import com.google.gson.Gson;就可以使用了。 对象转换为Json字符串: String strTmp = gson.toJson(content); out.write(strTmp.getBytes()); // TODO: handle exception Log.d("error","writeHeaderFromSocket" + e.getMessage());
Json字符串转换为对象: byte[] tempbuffer = new byte[MAX_BUFFER_BYTES]; int numReadedBytes = in.read(tempbuffer, 0, MAX_BUFFER_BYTES); String strJson = new String(tempbuffer, 0, numReadedBytes, "utf-8"); MyType myType = gson.fromJson(strJson, MyType.class);
Json字符串转换为List<T>: byte[] tempbuffer = new byte[MAX_BUFFER_BYTES]; int numReadedBytes = in.read(tempbuffer, 0, MAX_BUFFER_BYTES); String strJson = new String(tempbuffer, 0, numReadedBytes, "utf-8"); List<MyType> listMyType = gson.fromJson(strJson, new TypeToken<List<MyType>>(){}.getType());
|