利用socket直接与adb的pc service通讯

原创 2015年07月09日 13:48:53

       平常我们使用命令行调用adb去获取信息或者是与手机通讯,了解过adb源码的都清除,在pc端的adb是有adb client和adb service两部分的,正常我们调用的都是adb的client,adb client自己内部会去查询adb service是否已经启动,如果没有就会去启动adb service,再利用socket去通讯,正常我们在代码里面需要利用管道去获取cmd里面adb返回的结果。

       本文就是在我们自己的代码里面直接利用socket与adb service通讯,绕过执行cmd和利用管道获取数据,这种方式在速度上面会快很多,基本原理就是参考adb的源码 把socket与adb service相关的代码移植到自己的工程里面,下面就是一个demo代码,真正移植到项目还需要修改。

(由于在公司有加密软件的原因,源代码只能以文本方式一部分一部分拷贝到博客,所有下面的布局会不清晰)

AdbSocketHelper.h

#pragma once
#include <Winsock2.h>//这个需要放在 windows.h前面
#include <string>
#include <vector>

using std::string;
using std::wstring;

class AdbSocketHelper
{
public:
 AdbSocketHelper(void);
 ~AdbSocketHelper(void);
 string getDevices();
 string getAdbVersion();

string adbShell(const string shellCmd,const string deviceSN);
 void setAdbPathAndPort(wstring wcspath,int server_port);
private:
 string executeAdb(const string cmd);
 string executeDeviceAdb(const string cmd,const string deviceSN);

 bool createAdbSocket(SOCKET &Socket,string &strError);
 int launch_server();
 SOCKET socketClient();
 bool executeSocket(const SOCKET Socket,const string cmd,bool recvLoop,string &strdata);
 bool sendSocketData(const SOCKET Socket,const string strdata);
 bool recvSocketDataOnce(const SOCKET Socket,string &strdata);
 bool recvSocketDataLoop(const SOCKET Socket,string &strdata);

int m_serverport;
 wstring m_wcspath;
 static bool iniSocketLib;
};

 

下面是AdbSocketHelper.cpp文件

#include "AdbSocketHelper.h"

#pragma comment(lib,"ws2_32.lib")
bool AdbSocketHelper::iniSocketLib = false;
#define MAX_BUF 1024*4+1

AdbSocketHelper::AdbSocketHelper(void)
{
 //test 的默认值设置
 m_serverport = 6037;
 m_wcspath = L"E:\\work\\adb\\LibAdb\\Debug\\LibAdb.exe";
}

AdbSocketHelper::~AdbSocketHelper(void)
{

}

void AdbSocketHelper::setAdbPathAndPort(wstring wcspath,int server_port)
{
 m_wcspath = wcspath;
 m_serverport = server_port;
}

string AdbSocketHelper::getAdbVersion()
{
 string retStr = executeAdb("host:version");
 return retStr;
}

string AdbSocketHelper::getDevices()
{
 string retStr = executeAdb("host:devices");
 return retStr;
}

string AdbSocketHelper::adbShell(string shellCmd,string deviceSN)
{
 string retStr;
 string realCmd = "shell:";
 realCmd+=shellCmd;
 string realdeviceSN = deviceSN;
 if (realdeviceSN.empty())
 {//0012host:transport-any
  realdeviceSN = "-any";
 }
 else
 {
  realdeviceSN = ":"+realdeviceSN;
 }
 
 retStr = executeDeviceAdb(realCmd,realdeviceSN);
 return retStr;
}

string AdbSocketHelper::executeAdb(const string cmd)
{
 string retStr;
 retStr.clear();
 SOCKET clientSocket = INVALID_SOCKET;
 if (createAdbSocket(clientSocket,retStr))
 {
  executeSocket(clientSocket,cmd,true,retStr);
  // 服务端会关闭,所以客户端每次都创建新的socket,用完就关闭
  closesocket(clientSocket);
 }
 return retStr;
}

string AdbSocketHelper::executeDeviceAdb(const string cmd,const string deviceSN)
{
 string retStr;
 retStr.clear();
 SOCKET clientSocket = INVALID_SOCKET;
 if (createAdbSocket(clientSocket,retStr))
 {
  //因为指定了 设备序列号,所以需要先host:transport
  string transportCmd = "host:transport";
  transportCmd += deviceSN;
  executeSocket(clientSocket,transportCmd,false,retStr);
  //需要执行两次
  executeSocket(clientSocket,cmd,true,retStr);
  // 服务端会关闭,所以客户端每次都创建新的socket,用完就关闭
  closesocket(clientSocket);
 }
 return retStr;
}

bool AdbSocketHelper::createAdbSocket(SOCKET &Socket,string &strError)
{
 bool bRet = true;
 Socket = socketClient();
 if (INVALID_SOCKET == Socket)
 {
  //socket 连接不上就 认为服务没有启动
  if (0==launch_server())
  {//启动服务 成功
  }
  else
  {
   strError = "Error:launch server fail.";
   bRet = false;
  }
 }
 return bRet;
}

bool AdbSocketHelper::executeSocket(const SOCKET Socket,const string cmd,bool recvLoop,string &strdata)
{
 bool bRet = true;
 if ((sendSocketData(Socket,cmd)))
 {
  if (recvLoop)
  {
   bRet = recvSocketDataLoop(Socket,strdata);
  }
  else
  {
   bRet = recvSocketDataOnce(Socket,strdata);
  }
 }
 else
 {
  bRet = false;
 }
 return bRet;
}

bool AdbSocketHelper::sendSocketData(const SOCKET Socket,const string strdata)
{
 //发送的数据前面需要添加 4位的 数据长度,这个是从adb源码获取的
 char tmpCharLen[5] = {0};
 _snprintf_s(tmpCharLen, sizeof tmpCharLen,4 ,"%04x",strdata.length());
 string realData(tmpCharLen);
 realData += strdata;
 int retVal = send(Socket,realData.c_str(),realData.length(),0);
 if (SOCKET_ERROR == retVal)
 {
  printf("sendSocketData %s error = %d\n",strdata.c_str(),WSAGetLastError());
  return false;
 }
 return true;
}

bool AdbSocketHelper::recvSocketDataOnce(const SOCKET Socket,string &strdata)
{
 bool bRet = true;
 char *buf = new char[MAX_BUF+1];
 ZeroMemory(buf, MAX_BUF+1);
 int retVal=recv(Socket,buf,MAX_BUF,0);
 if (SOCKET_ERROR == retVal )
 {
  //接收出错了
  printf("recvSocketData recv error %d\n",WSAGetLastError());
  bRet = false;
 }
 else
 {
  if(0 == memcmp(buf, "OKAY", 4))
  {

  }
  else
  {
   strdata.append(buf);
   bRet = false; //状态错误
  }
 }
 return bRet;
}

 

bool AdbSocketHelper::recvSocketDataLoop(const SOCKET Socket,string &strdata)
{
 bool bRet = true;
 strdata.clear();
 char *buf = new char[MAX_BUF+1];
 bool isFist = true;
 int DataLen;
 while(1)
 {
  ZeroMemory(buf, MAX_BUF+1);
  int retVal=recv(Socket,buf,MAX_BUF,0);
  if (SOCKET_ERROR == retVal )
  {
   //接收出错了
   printf("recvSocketData recv error %d\n",WSAGetLastError());
   bRet = false;
   break;
  }

else if (0 == retVal)
  {
   //数据接收完成了
   break;
  }
  else
  {
   if (isFist)
   {
    isFist = false;
    if(0 == memcmp(buf, "OKAY", 4))
    {//应该接收到的数据长度
     char tmp[5] = {0};
     memcpy(tmp,buf+4,4);
     DataLen = strtol(tmp, NULL, 16);
    }
    else
    {
     bRet = false; //状态错误
    }
   }
   else
   {
    strdata.append(buf);
   }
  }
 }
 delete [] buf;
 
 if (DataLen != strdata.length())
 {
  printf("recvSocketData  data length is error \n");
 }
 return bRet;
}

SOCKET AdbSocketHelper::socketClient()
{
 SOCKET clientSocket = INVALID_SOCKET;
 if (!iniSocketLib)
 {
  //加载socket库函数
  WORD wVersionRequested;
  WSADATA wsaData;
  int err;
  wVersionRequested = MAKEWORD(2,2);
  err = WSAStartup( wVersionRequested, &wsaData );
  if ( err != 0 )
  {                          
   printf("WSAStartup fail ... %d \n",WSAGetLastError());
   return clientSocket;
  }
  else
  {
   iniSocketLib = true;
  }
 }

// 创建套接字
 if ((clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))   ==   INVALID_SOCKET)    
 {  
  printf("socket()   failed   with   error   %d\n",   WSAGetLastError());  
 }
 else
 {
  SOCKADDR_IN   InternetAddr;
  memset(&InternetAddr, 0, sizeof(InternetAddr));
  InternetAddr.sin_family = AF_INET;
  InternetAddr.sin_port = htons(m_serverport);
  InternetAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

  int retVal;

//连接服务器
  retVal = connect(clientSocket, (LPSOCKADDR)&InternetAddr, sizeof(InternetAddr));
  if (SOCKET_ERROR == retVal)
  {
   printf("connect() socket failed  with   error   %d\n",   WSAGetLastError());  
   closesocket(clientSocket);
   clientSocket = INVALID_SOCKET;
  }
 }
 return clientSocket;
}

//启动服务 这个是从adb源码里面获取出来的,修改了部分
int AdbSocketHelper::launch_server()
{
    HANDLE                pipe_read, pipe_write;
    HANDLE                stdout_handle, stderr_handle;
    SECURITY_ATTRIBUTES   sa;
    PROCESS_INFORMATION   pinfo;
    int                   ret;
    STARTUPINFOW    startup;
    wchar_t               program_path_unicode[MAX_PATH] = {0};
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    /* create pipe, and ensure its read handle isn't inheritable */
    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );

if (!ret) {
        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
        return -1;
    }

    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );

  ZeroMemory( &pinfo, sizeof(pinfo) );
  ret = CreateProcessW(m_wcspath.c_str(),L"adb fork-server server",NULL,NULL,TRUE,DETACHED_PROCESS,NULL,NULL,&startup,&pinfo);

    CloseHandle( pipe_write );

if (!ret) {
        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
        CloseHandle( pipe_read );
        return -1;
    }

    CloseHandle( pinfo.hProcess );
    CloseHandle( pinfo.hThread );

/* wait for the "OK\n" message */
    {
        char  temp[3];
        DWORD  count;

        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
        CloseHandle( pipe_read );
        if ( !ret ) {
            fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
            return -1;
        }
        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
            fprintf(stderr, "ADB server didn't ACK\n" );
            return -1;
        }
    }
    return 0;
}

 

下面是测试代码,测试代码只是测试了两个命令,测试代码很简单

 AdbSocketHelper adbHelper;
 adbHelper.setAdbPathAndPort(L"E:\\work\\adb\\LibAdb\\Debug\\Adb.exe",5037);
string strRet;
 
 strRet = adbHelper.getAdbVersion();
 printf("%s\n",strRet.c_str());
 strRet = adbHelper.getDevices();
 printf("%s\n",strRet.c_str());
 strRet = adbHelper.adbShell("dumpsys iphonesubinfo","");
 printf("%s\n",strRet.c_str());

简单的把手机连接到电脑,安装好驱动,就能获取到adb的版本信息和当前的设备列表。

其他的adb命令可以参考adb的源码来完善,这里只是给出一个demo,需要在项目中使用的时候,直接把上面的类添加到工程,补充其他的adb命令即可。

手机与pc USB连接adb socket通信

手机通过usb线连接pc,实现pc主动向手机发送消息;   一、获取与电脑连接的所有手机   public static List findDevices(){ Listdevices ...
  • hsp1990
  • hsp1990
  • 2014年03月24日 18:49
  • 9088

利用ddmlib 实现 PC端与android手机端adb forword socket通信

当PC与手机连通时,我们可以通过Socket连接来实现PC与手机间的通信。   这里我们先讨论手机做为Server端、PC做为Client端的情况。   和其他Java Soc...
  • g19920917
  • g19920917
  • 2014年09月16日 09:37
  • 2017

PC和Android adb通信

adb forward命令的理解和使用,PC创建端口映射到android设备上,可以高效的进行数据传输。...
  • obanaganastar
  • obanaganastar
  • 2016年12月06日 13:26
  • 2298

PC与Android设备通过USB建立通信连接

通过adb的adb forward指令可以方便的通过USB连接建立PC端与Android的连接。
  • guokehello
  • guokehello
  • 2016年04月21日 14:23
  • 4608

Android通过USB与PC通信

最近项目中有一个功能需要用到Android与PC端同步数据。查阅了相关资料后,采取了一种建立在adb基础之上的Usb通信方式:由于adb可以将Usb模拟为网卡,所以可以利用socket通信的方式实现A...
  • snail200802101
  • snail200802101
  • 2013年12月11日 23:04
  • 9487

android用socket与PC用C#的socket通讯使PC关机

因为本人有时候开着电脑就会床上玩手机,突发奇想用手机控制电脑关机,说写就写,虽然对android编程刚开始不懂,但是android出了个神器编译环境(android studio),比以前的eclip...
  • gaoweiweiw
  • gaoweiweiw
  • 2016年11月14日 15:31
  • 941

PC 与 Android 的adb同步通信(一)

公司只能上csdn,作为中转站传资料。原文地址http://www.yidin.net/discuz/forum.php?mod=viewthread&tid=172&extra=page%3D1 ...
  • FANCHUANLIN2000
  • FANCHUANLIN2000
  • 2015年01月03日 14:56
  • 1978

Android开发-通过ADB+Socket实现USB数据传输

通过ADB+Socket实现USB数据传输
  • adzcsx2
  • adzcsx2
  • 2015年09月16日 15:40
  • 917

Android Socket 编程(WIFI 和 ADB)

昨天正式开始 Android 编程学习与实践,由于 Android 模拟器在 WinXP 下一直未安装成功,所在将闲置很久的 Android 手机: 联想 A750 手机找到用于调试。A750 是 A...
  • 91program
  • 91program
  • 2014年09月10日 09:44
  • 6040

android adb 通信原理

adb 源码system/core/adb adb是client-server构架,包含三个部分 1、client 运行于开发机器 2、server 作为后台进程同样运行于开发机器,server负责管...
  • Clovelegent
  • Clovelegent
  • 2016年09月12日 18:22
  • 938
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用socket直接与adb的pc service通讯
举报原因:
原因补充:

(最多只允许输入30个字)