1、 adb forward 原理概述
adb forward 的功能是建立一个转发
如:adb forward tcp:8000 tcp:9000 的意思是,将PC端的 8000 端口收到的数据,转发给手机中的 9000 端口。
但是光执行这个命令还不能转发数据,还需要完成下面两个步骤才能传数据:
(a)在手机端,建立一个端口为9000的 server,并打开 server 到监听状态。
(b)在PC端,建立一个 socket client 端,连接到端口为8000的 server 上。
adb forward tcp:8000 tcp:9000 原理示意图:
PC端应用与手机端应用 通信建立过程:
(1)执行 adb forward tcp:8000 tcp:9000
(2)启动手机端应用,建立端口为9000的 server,并处于监听状态(LISTENING)
(3)启动PC端应用,连接端口为8000的 server(adb 创建的)之后,就可以传输数据了
PC端代码====
private static boolean mRunning = true;
public static void main(String[] args) {
if (!setupAdbForward()) {
System.out.println("设置端口转发失败");
return;
} else {
System.out.println("端口转发设置完成");
}
System.out.println("任意字符, 回车键发送");
startClient();
}
private static boolean setupAdbForward() {
try {
// todo 将PC端8000端口的数据, 转发到Android端的9000端口上
String device = "adb devices";
Process process = Runtime.getRuntime().exec(new String[]{"cmd", "/c", device});
int ret = process.waitFor();
System.out.println("cmy 111:" + device + ";" + ret);
String forward = "adb forward tcp:8000 tcp:9000";
process = Runtime.getRuntime().exec(new String[]{"cmd", "/c", forward});
process.waitFor();
System.out.println("cmy 222:" + forward + ";" + ret);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static void startClient() {
try {
//设置pc端的端口为8000
Socket socket = new Socket("127.0.0.1", 8000);
// InThread 接收手机端传来的数据
new Thread(new InThread(socket)).start();
// OutThread 用于从PC端输入并传给手机端
Scanner scanner = new Scanner(System.in);
while (true) {
String msg = scanner.next();
sendToServer(socket, msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 接收手机端传来的数据
*/
static class InThread implements Runnable {
Socket socket;
public InThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (mRunning) {
if (socket.isClosed()) {
mRunning = false;
break;
}
try {
DataInputStream dis = new DataInputStream(socket.getInputStream());
byte[] buffer = new byte[256];
int len = dis.read(buffer);
if (len > 0) {
System.out.println("\n接收到:" + new String(buffer, 0, len, "UTF-8"));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 从PC端输入并传给手机端
*
* @param msg 信息
* @throws IOException 异常
*/
public static void sendToServer(Socket socket, String msg) throws IOException {
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(msg);
dos.flush();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
PC端应用与手机端应用之间传输数据的过程:
(1)PC端应用将数据发送给端口为8000的 server(adb 创建的)
(2)adb 将数据转发给手机端 adbd 进程(通过USB传输)
(3)adbd 进程将数据发送给端口为9000的 server(手机端应用创建的)传递是双向的,
第(1)和第(3)步是通过socket实现的,所以通过 socket 的读和写就完成了PC端和手机端的数据传递。
=======andorid 端代码=
public class ServerThread extends Thread {
private static final String SERVER_TAG = "server";
private ServerSocket serverSocket;
private Socket socket;
boolean isLoop = true;
public Socket getSocket() {
return socket;
}
@Override
public void run() {
super.run();
try {
//设置Android端口为9000
serverSocket = new ServerSocket(9000);
while (isLoop) {
try {
//从连接队列中取出一个连接,如果没有则等待
socket = serverSocket.accept();
Log.v(SERVER_TAG, "从连接队列中取出一个连接");
EventBus.getDefault().post(new MessageType("发现一个新的客户端加入:"));
while (true) {
/**
* isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()
* 这些方法无法判断服务端是否断开,只能判断本地的状态
*/
// 发送心跳包,单线程中使用,判断socket是否断开
socket.sendUrgentData(0xFF);
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
byte[] buffer = new byte[1024];
int bt;
String text = "";
int index = 0;
Log.v(SERVER_TAG, "inputStream.read 之前");
while ((bt = inputStream.read(buffer)) != -1) {
Log.v(SERVER_TAG, "bt:" + bt + ",," + (index++));
text += new String(buffer, 0, bt).trim();
Log.e(SERVER_TAG, "------------");
Log.e(SERVER_TAG, "text: " + text.trim());
/**
* 当接收到大数据,inputStream读取完后,由于inputStream通道是一直在的,
* inputStream.read(buffer)处在堵塞状态,所以并不会跳出当前循环,
* 导致无法判断数据是否传输完,所以PC端传输数据时需要在数据中
* 加入报尾,Android设备上接收到报尾,代表此次数据传输完毕,
* 也可以加上报头,来表示数据的开始
*
*/
if (text.endsWith("-vvv")) {
EventBus.getDefault().post(new MessageType("接收:" + text));
text = text.substring(0, text.lastIndexOf("-vvv"));
Log.v(SERVER_TAG, "内容长度:" + text.length());
Log.v(SERVER_TAG, "读取结束,内容为:" + text);
Log.v(SERVER_TAG, "inputStream.read 之后");
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
EventBus.getDefault().post(new MessageType("接收:异常"));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class SendThread extends Thread {
private String data;
private Socket socket;
public SendThread(String data, Socket socket) {
this.data = data + "-vvv";
this.socket = socket;
}
@Override
public void run() {
super.run();
sendDatas();
}
private void sendDatas() {
try {
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.write(data.getBytes("UTF-8"));
outputStream.flush();
LogUtils.e("发送:" + data);
EventBus.getDefault().post(new MessageType("发送:" + data));
} catch (IOException e) {
e.printStackTrace();
EventBus.getDefault().post(new MessageType("发送:异常"));
}
}
}