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

安卓设备和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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值