您的位置:首页 > 编程语言 > C语言/C++

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

2015-07-09 13:48 357 查看
       平常我们使用命令行调用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命令即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  adb c++ socket 手机助手