安卓与PC使用USB一种Socket通信方案

来源:互联网 发布:php 菜鸟教程 编辑:程序博客网 时间:2024/06/06 01:06

安卓设备和PC之间有很多种通信方式,比如基于无线网络等等。有的时候我们可能需要一些其他的通信方式。安卓设备和PC之间可以通过使用USB来进行通信。使用USB通信能够比无线通信速度更快,效率更高,这一点在分布式中的研究中很有用处,比如我们使用多台手机做实验,记录下log,这几个log的时间最好是一样的,那么我们可以每次记录下log的时候,向PC获取一次时间,把PC的时间作为标准时间。以下给出基于USB通信的原理和实现方式。

通信原理与机制

安卓设备能够和PC之间使用Socket通信的关键一点是能够使用adb转发,所以手机要有adb模式。adb对端口进行映射,转发Socket中的数据,在Socket通信结构中,PC端只能作为Client端,安卓设备是作为Server端。

具体实现

先看安卓端的实现,安卓端的步骤是建立服务端的监听过程,在连接上之后做各种处理。代码如下:

ServerSocket serverSocket = new ServerSocket(ADBExecutor.ANDROID_PORT);Socket socket = serverSocket.accept();SomeService.INSTANCE.setIOStream(socket);

这里ADBExecutor.ANDROID_PORT是自己定义的一个端口,这个用户自己随意定义。对于SomeService类也在这里给出代码吧:

public enum SomeService {    INSTANCE;    private DataInputStream inputStream = null;    private DataOutputStream outputStream = null;    public void setIOStream(final Socket socket){        try {            inputStream = new DataInputStream(socket.getInputStream());            outputStream = new DataOutputStream(socket.getOutputStream());        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    public void pollingTime(){        try {            outputStream.writeUTF("REQ");            outputStream.flush();            long time = inputStream.readLong();            System.out.println("PC time:" + time + "  \n");        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

可以在这中间做想要的事情。比如我定义了一个方法为pollingTime(),就是获取PC的时间并打印。

接下来看PC端的代码的操作。在PC端需要首先确定有哪些设备通过USB连接上的,这个可以得到当前连接的设备的机器序列号。然后通过执行如下命令:

adb -s device_id forward tcp:host_port tcp:to_port

来完成端口的转发映射。其中device_id就是对应的机器的硬件地址。host_port是PC定义的一个端口,to_port是指定的转发到的端口。而关于device_id怎么得到呢,执行如下命令即可:

adb devices

关于怎么在java中执行命令,以及收集命令执行的结果,建立端口的映射,建立Socket连接,给出如下代码:

public class ADBExecutor {    public static final int ANDROID_PORT = 30000;    public static final int HOST_BASE_PORT = 35000;    private final String adb_directory;    public ADBExecutor(String adb_directory){        this.adb_directory = adb_directory;    }    //得到当前连接上的设备的序列号    public List<String> execAdbDevices()    {        System.out.println("adb devices");        List<String> ret_device_id_list = new ArrayList<String>();        Process proc = null;        try        {            proc = new ProcessBuilder(this.adb_directory, "devices").start();            proc.waitFor();        } catch (IOException ioe)        {            ioe.printStackTrace();        } catch (InterruptedException ire)        {            ire.printStackTrace();        }        String devices_result = this.collectResultFromProcess(proc);        String[] device_id_list = devices_result.split("\\r?\\n");        if (device_id_list.length <= 1)        {            System.out.println("No Devices Attached.");            return ret_device_id_list;        }        /**         * collect the online devices          */        String str_device_id = null;        String device = null;        String[] str_device_id_parts = null;        // ignore the first line which is "List of devices attached"        for (int i = 1; i < device_id_list.length; i++)        {            str_device_id = device_id_list[i];            str_device_id_parts = str_device_id.split("\\s+");            // add the online device            if (str_device_id_parts[1].equals("device"))            {                device = str_device_id_parts[0];                ret_device_id_list.add(device);                System.out.println(device);            }        }        //System.exit(0);        return ret_device_id_list;    }    //对于当前连接上的设备都进行映射    public Map<String, Integer> execAdbOnlineDevicesPortForward()    {        List<String> device_id_list = this.execAdbDevices();        Map<String, Integer> device_hostport_map = new HashMap<String, Integer>();        int index = 0;        for (String device : device_id_list)        {            int host_port = ADBExecutor.HOST_BASE_PORT + index * 10;            this.execAdbSingleDevicePortForward(device, host_port, ADBExecutor.ANDROID_PORT);            device_hostport_map.put(device, host_port);            index++;        }        return device_hostport_map;    }    //具体的映射过程    public void execAdbSingleDevicePortForward(String device_id, int host_port, int to_port)    {        System.out.println("adb -s " + device_id + " forward tcp:" + host_port + " tcp:" + to_port);        Process proc = null;        try        {            proc = new ProcessBuilder(this.adb_directory, "-s", device_id, "forward", "tcp:" + host_port, "tcp:" + to_port).start();            proc.waitFor();        } catch (IOException ioe)        {            ioe.printStackTrace();        } catch (InterruptedException ire)        {            ire.printStackTrace();        }    }    //手机命令执行之后的结果    private String collectResultFromProcess(Process proc)    {        StringBuilder sb_result = new StringBuilder();        BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));        BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));        String result_line = null;        try        {            while ((result_line = stdInput.readLine()) != null)             {                sb_result.append(result_line);                sb_result.append("\n");            }            while ((result_line = stdError.readLine()) != null)             {                sb_result.append(result_line);                sb_result.append("\n");            }        } catch(IOException ioe)        {            ioe.printStackTrace();        }        return sb_result.toString();    }}

以上是ADB执行各种操作的类,比如查看当前连接的设备,建立端口映射。接下来给出PC上执行的主要过程:

package com.example.adbforward;import java.io.IOException;import java.net.Socket;import java.net.UnknownHostException;import java.util.HashMap;import java.util.Map;public class PCHost {    private final Map<String, Integer> device_hostport_map;    private final Map<String, Socket> device_hostsocket_map = new HashMap<String, Socket>();    public PCHost(Map<String, Integer> device_hostport_map){        this.device_hostport_map = device_hostport_map;        this.createDeviceHostConnection();    }    //创建连接    private void createDeviceHostConnection()    {        String device = null;        int host_port = -1;        for(Map.Entry<String, Integer> device_hostport : this.device_hostport_map.entrySet())        {            device = device_hostport.getKey();            host_port = device_hostport.getValue();            Socket device_hostsocket = null;            try            {                device_hostsocket = new Socket("localhost", host_port);            } catch (UnknownHostException uhe)            {                uhe.printStackTrace();            } catch (IOException ioe)            {                ioe.printStackTrace();            }            this.device_hostsocket_map.put(device, device_hostsocket);        }    }    public void startTimeService(){        //启动某些服务线程    }    public static void main(String[] args) throws InterruptedException    {        ADBExecutor adb_executor = new ADBExecutor("E:\\eclipse\\sdk\\platform-tools\\adb.exe ");//这是我的abd.exe的位置        Map<String, Integer> device_hostport_map = adb_executor.execAdbOnlineDevicesPortForward();        final PCHost host = new PCHost(device_hostport_map);        host.startTimeService();    }}

以上就是整个android和PC之间通过USB采用Socket通信的主要过程。给出的代码能够对连接在PC上的多个设备都开启服务,即如果有多个设备连接在PC上。以上来自师兄的指点,在此感谢。

0 0
原创粉丝点击