Android中通过USB接口与和PC进行通讯的demo程序

以往开发过多款安卓嵌入式设备,这些设备与PC通讯主要通过设备上的以太网网口进行网络通讯,最近一个项目设备没有以太网网口,设备与PC通讯要求使用普通安卓数据线连接设备与PC完成数据通讯。

查阅相关资料以及对adb操作指令的了解,最终实现了项目需求。

方案实现思路:

1.设备端开启一个socket服务,服务端口12345;

2.设备端监听USB插拔事件来启动关闭设备端的socket服务;

3.PC端使用adb命令:adb forward tcp:54321 tcp:12345,将PC端口54321上发来的数据转换到设备socket服务端口;

4.PC端启动socket客户端与PC端口54321进行数据通讯。

因为项目代码保密,故对方案实现特意写了一个demo程序。

Demo实现了:

1.安卓设备端socket服务,服务监听端口12345,收到任何消息,均回复设备的毫秒时间戳。

2.PC 实现使用adb命令将PC端口54321消息转发到设备服务端口12345,之后,连接socket连接,并监听端口54321的消息,每隔3s发送PC毫秒时间戳,并监听设备端服务回应的数据。

以下以代码进行进行介绍。

Android端:

package com.yx.usb2pc;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.util.Log;

/**
 * UsbConnectReceiver
 * 主要监听ACTION_USB_STATE,启动关闭socket服务
 *
 * @author yx
 * @date 2019/10/30 20:39
 */
public class UsbConnectReceiver extends BroadcastReceiver {
    private static final String TAG = "UsbConnectReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.hasExtra(UsbManager.EXTRA_PERMISSION_GRANTED)) {
            boolean permissionGranted =
                    intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
            Log.v(TAG, "permissionGranted : " + permissionGranted);
        }
        String action = intent.getAction();
        Log.v(TAG, "action:" + action);
        switch (action) {
            case UsbManager.ACTION_USB_ACCESSORY_ATTACHED:
            case UsbManager.ACTION_USB_ACCESSORY_DETACHED:
                UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                Log.v(TAG, accessory.toString());
                break;
            case UsbManager.ACTION_USB_DEVICE_ATTACHED:
                Log.v(TAG, UsbManager.ACTION_USB_DEVICE_ATTACHED);
                break;
            case UsbManager.ACTION_USB_DEVICE_DETACHED:
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                Log.v(TAG, device.toString());
                break;
            case UsbManager.ACTION_USB_STATE:
                boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
                boolean functionAdb = intent.getBooleanExtra(UsbManager.USB_FUNCTION_ADB, false);
                Log.v(TAG, "connected:" + connected + " function_adb : " + functionAdb);
                // 断开停止服务
                if (!connected) {
                    SocketServer.getSocketServerInstant().stopServer();
                } else {
                    // 开启adb调试功能,开启服务
                    if (functionAdb) {
                        SocketServer.getSocketServerInstant().startServer();
                    }
                }
                break;
            default:
                break;
        }
    }
}
UsbConnectReceiver,广播接收器,监听UsbManager.ACTION_USB_STATE状态变化,如果连接断开(connected==false),关闭设备端的socket服务,当然已连接上需要判断adb功能是否使能才能开启服务。
package com.yx.usb2pc;

import android.util.Log;

import com.yx.usb2pc.utils.ThreadPoolManager;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * SocketServer
 * 服务端接收socket信息,回复设备端的时间戳信息
 *
 * @author yx
 * @date 2019/10/30 20:39
 */
public class SocketServer {
    private static final String TAG = "SocketServer";
    private static final int PORT = 12345;
    private ServerSocket mServerSocket = null;
    private boolean mRunning = false;

    private static SocketServer sSocketServer;

    public static SocketServer getSocketServerInstant() {
        if (sSocketServer == null) {
            sSocketServer = new SocketServer();
        }
        return sSocketServer;
    }

    private SocketServer() {
    }

    /**
     * 启动服务
     */
    public void startServer() {
        stopServer();
        ThreadPoolManager.getInstance().startTaskThread(new ServerThread(), "server-thread");
    }

    /**
     * 关闭服务
     */
    public void stopServer() {
        if (mServerSocket != null) {
            mRunning = false;
            try {
                mServerSocket.close();
                Log.d(TAG, "stopServer server ");
            } catch (Exception e) {
                e.printStackTrace();
            }
            mServerSocket = null;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    class ServerThread extends Thread {

        @Override
        public void run() {
            mRunning = true;
            try {
                mServerSocket = new ServerSocket(PORT);
                Log.d(TAG, "start server port = " + PORT);
                while (mRunning) {
                    Socket socket = mServerSocket.accept();
                    Log.d(TAG, "accept ");
                    ThreadPoolManager.getInstance()
                            .startTaskThread(new ReceiveThread(socket), "receive-thread");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (mServerSocket != null) {
                    try {
                        mServerSocket.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    class ReceiveThread extends Thread {
        private Socket socket;

        public ReceiveThread(Socket socket) {
            this.socket = socket;
            Log.d(TAG, " socket:" + socket.toString());
        }

        @Override
        public void run() {
            try {
                DataInputStream dis = new DataInputStream(socket.getInputStream());
                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

                while (true) {
                    String data = dis.readUTF();
                    Log.d(TAG, "receive:" + data);
                    // 接收到后回复设备的毫秒时间戳
                    String s = "device:" + System.currentTimeMillis();
                    dos.writeUTF(s);
                    dos.flush();
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
SocketServer设备端socket服务,主要提供服务开启关闭方法,服务开启后ServerThread会循环侦听数据消息,每侦听到消息开启一个ReceiveThread线程处理数据,demo中数据接收到后回复设备的毫秒时间戳。

PC端:

package com.yx.soclectclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * SocketClient
 * 

* PC端每隔3s给监听端口发送PC时间戳信息 * * @author yx * @date 2019/5/17 13:57 */ public class SocketClient { private Socket mSocket = null; private static final int PORT = 54321; /** * adb 命令绑定端口 * * @return */ private boolean adbForward() { String cmd = "adb forward tcp:54321 tcp:12345"; try { Runtime.getRuntime().exec(cmd); } catch (IOException e) { e.printStackTrace(); } Process process = null; try { process = Runtime.getRuntime().exec(cmd); process.waitFor(); return true; } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } finally { if (process != null) { process.destroy(); } } return false; } private void test() { try { mSocket = new Socket("127.0.0.1", PORT); System.out.println("socket:" + mSocket.toString()); DataInputStream dis = new DataInputStream(mSocket.getInputStream()); DataOutputStream dos = new DataOutputStream(mSocket.getOutputStream()); while (true) { String data = "sendTime:" + System.currentTimeMillis(); dos.writeUTF(data); dos.flush(); String s = dis.readUTF(); System.out.println("receive:" + s); Thread.sleep(3000); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { SocketClient client = new SocketClient(); if (client.adbForward()) { client.test(); } } }

SocketClient为PC端测试类,主要完成adb命令完成端口绑定,建立socket客户端连接,连接指向端口54321。连接后,每隔3s向端口发送PC时间戳,并侦听端口数据恢复。

ps:

1.本demo代码,android sdk版本为25;

2.因为测试时连接相对稳定,故未考虑socket长连接心跳问题及断线重连问题,可靠性应用需考虑心跳及断线重连问题。

3.PC端需要按照adb环境,使用时android设备需要打开adb调试模式。

4.USB数据线模拟网线进行socket通讯关键点是利用adb端口绑定命令:adb forward tcp:[pc port] tcp:[device port]。

5.demo源码:https://github.com/TomcatXiong/UsbPcCommunicationDemo

Android中通过USB接口与和PC进行通讯的demo程序_第1张图片 扫描关注更精彩

 

 

你可能感兴趣的:(android,Java)