本地套接字,在线手动调试主程序

一个已经串联起来一堆功能的程序,现在想修改其中某一个模块的功能,比如音视频编码在程序已经运行的过程中动态调整码率,没有完善的单元测试接口,着实苦恼,想到一个简单的方式,在现有的代码上嵌入一个local socket 服务,另外写一个小程序connect进去给它发信息,来触发我们实现的功能调用,如此即可手动在线调试。 (这不是gdb等的debug调试,也就是一个进程间通信的应用)
上代码:
个人在android上调试jni库的一个功能调用使用,用ndk编译之后将编译的debug_client可执行文件push到设备运行,发信息给主程序中的server来触发接口调用。
有几处坑:

1.0 该套接字就像 pipe管道一样,需要一个路径创建该文件,(以下代码中的宏定义SOCKET_FILE_PATH)在android系统中,
放/storage/emulated/0/ 目录,不可行,该目录所有的文件都没有执行权限
放 system/ 目录也不行,最后个人是放在了 /data 目录。另外,服务端启动前要把
selinux 关掉,#setenforce 0 不然在accept的时候会报错,参数不合法. 可执行文件debug_client 执行前修改权限chmod 777 debug_client, 也不能在/storage/emulated/0/目录, 不然根本修改不了其权限。 
2.0 客户端 scanf, scanf完之后要把stdin 多余的数据清空,不然会影响下一次输入
3.0 Android.mk 需要加 LOCAL_LDFLAGS += -pie -fPIE, 位置无关码,不然在adroid 5.0 以上会提示错误

 

//DebugOnline.h
#ifndef __Debugonline_h__ 
#define __Debugonline_h__
namespace android {

class DebugOnline{
	public :
		DebugOnline();
		~DebugOnline();
};
}
#endif
//canok 20210121
//server.cpp  服务端,用来嵌入到原代码
//#define LOG_TAG "DebugOnline"
//#include <utils/Log.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>

#include <errno.h>
#include <pthread.h>

#include"DebugOnline.h"

namespace android {

struct s_cmd{
	int type;
	char c_data;
	int i_data0;
	int i_data1;
	char s_data[128];
};
int readSocket(  int socket,   char* buffer, unsigned bufferSize,
	       struct sockaddr *fromAddress){
	socklen_t addrlen = sizeof( struct sockaddr);
	int bytesRead = recvfrom(socket, buffer, bufferSize, 0,
                       fromAddress, &addrlen);
	if(bufferSize < 0){//erro
		printf("err:%d:%s\n",errno,strerror(errno));
	}
	return bytesRead;
}
		   
int writeSocket(int socket,char* buffer, unsigned bufferSize,
				struct sockaddr * destAddress) {
	socklen_t addrlen = sizeof( struct sockaddr);
	int bytesSent = sendto(socket, (char*)buffer, bufferSize, 0,
			  destAddress, addrlen);
	if (bytesSent != (int)bufferSize) {//erro
		printf("writeSocket erro %d/%d \n",bytesSent,bufferSize);
	}
	return bytesSent;
}

//返回 true表示成功,false,表示没有成功读到所需长度的数据量,比如对方socket已经关闭,返回false
bool loopRead(int fd, char*buf, int size){
	int ret =0;
	int count =0;
	int trytimes = 50;//在读不到指定长度数据,重复读取的次数。
	while(count < size){
		ret = readSocket(fd,buf+count,size-count,NULL);
		printf("readed data ret:%d\n",ret);
		if(ret <= 0){
			//读出错
			printf("erro read \n");
			return false;
		}
		if(!trytimes--){
			printf("read times out!!\n");
			return false;
		}
		count+=ret;
	};
	return true;
}

bool loopWrite(int fd,char *buf, int size){
	int ret =0;
	int count =0;
	int trytimes = 50;//重复的次数。
	while(count < size){
		ret = writeSocket(fd,buf+count,size-count,NULL);
		if(ret <= 0){
			//写出错
			printf("erro");
			return false;
		}
		if(!trytimes--){
			printf("write times out!!");
			return false;
		}
		count+=ret;
	};
	return true;
}

#define SOCKET_FILE_PATH "/data/DEBUG_SERVER"
void* DebugOnline_thread (void *p){
	DebugOnline* debug=(DebugOnline*)p;
	int server_sockfd, client_sockfd;
	int server_len, client_len;
	struct sockaddr_un server_address; /*声明一个UNIX域套接字结构*/
	struct sockaddr_un client_address;
	int i, bytes;
	char ch_send, ch_recv;

	unlink (SOCKET_FILE_PATH); /*删除原有server_socket对象*/

	/*创建 socket, 通信协议为AF_UNIX, SCK_STREAM 数据方式*/
	server_sockfd = socket (AF_UNIX, SOCK_STREAM, 0);

	/*配置服务器信息(通信协议)*/
	server_address.sun_family = AF_UNIX;

	/*配置服务器信息(socket 对象)*/
	strcpy (server_address.sun_path, SOCKET_FILE_PATH);

	/*配置服务器信息(服务器地址长度)*/
	server_len = sizeof (server_address);

	/*绑定 socket 对象*/
	bind (server_sockfd, (struct sockaddr *)&server_address, server_len);

	/*监听网络,队列数为1  只允许一个用户控制*/
	listen (server_sockfd, 1);

	client_len = sizeof (client_address);
	while(1){
		 printf ("canok Server is waiting for client connect...\n");
		/*接受客户端请求; 第2个参数用来存储客户端地址; 第3个参数用来存储客户端地址的大小*/
		/*建立(返回)一个到客户端的文件描述符,用以对客户端的读写操作*/
		client_sockfd = accept (server_sockfd, (struct sockaddr *)&server_address, (socklen_t *)&client_len);
		if (client_sockfd == -1) {
			perror ("accept");
			printf("err:%d:%s\n",errno,strerror(errno));
			return NULL;
		}

		printf ("canok The server is waiting for client data...\n");
		char buf[256]={0};
		while(1){//处理当前客户端的请求。 
			memset(buf,0,sizeof(buf));
			if(!loopRead(client_sockfd,buf,sizeof(struct s_cmd))){
				//客户端已经关闭
				break;
			}
			struct s_cmd *pCmd = (struct s_cmd*)buf; 
			printf("type:%d, c_data %c, idata:%d,%d, s_data:%s\n",pCmd->type,pCmd->c_data,pCmd->i_data0,pCmd->i_data1,pCmd->s_data);
			if(pCmd->type == 1 ){
				//在这里调用要动态调试的接口
				printf("get cmd1\n");
			}else if(pCmd->type ==2){
				printf("get cmd2 ,send result\n");
				//可以返回调用后的结果
				char*pBuffer = (char*)pCmd;
				loopWrite(client_sockfd,pBuffer,sizeof(struct s_cmd));
			}
		}
		close (client_sockfd);
	}
	close(server_sockfd);
	unlink (SOCKET_FILE_PATH);
}

DebugOnline::DebugOnline(){
	pthread_t pid;
	pthread_create(&pid,NULL,DebugOnline_thread,this);
	pthread_detach(pid);
}
DebugOnline::~DebugOnline(){
}

}
using namespace android;
int main(){
	DebugOnline * debug = new DebugOnline();
	while(1){
		usleep(1000);
	}
}
//canok 20210121
//cleent.cpp
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>

#include <errno.h>
struct s_cmd{
        int type;
        char c_data;
        int i_data0;
        int i_data1;
        char s_data[128];
};

int readSocket(  int socket,   char* buffer, unsigned bufferSize,
	       struct sockaddr *fromAddress){
	socklen_t addrlen = sizeof( struct sockaddr);
	int bytesRead = recvfrom(socket, buffer, bufferSize, 0,
                       fromAddress, &addrlen);
	if(bufferSize < 0)
	{//erro
		printf("err:%d:%s\n",errno,strerror(errno));
	}
	return bytesRead;
}
		   
int writeSocket(int socket,char* buffer, unsigned bufferSize,
				struct sockaddr * destAddress) {
	socklen_t addrlen = sizeof( struct sockaddr);
	int bytesSent = sendto(socket, (char*)buffer, bufferSize, 0,
			  destAddress, addrlen);
	if (bytesSent != (int)bufferSize) 
	{//erro
		printf("writeSocket erro %d/%d \n",bytesSent,bufferSize);
	}
	return bytesSent;
}

//返回 true表示成功,false,表示没有成功读到所需长度的数据量,比如对方socket已经关闭,返回false
bool loopRead(int fd, char*buf, int size){
	int ret =0;
	int count =0;
	int trytimes = 50;//在读不到指定长度数据,重复读取的次数。
	while(count < size){
		ret = readSocket(fd,buf+count,size-count,NULL);
		//printf("readed data ret:%d\n",ret);
		if(ret <= 0){
			//读出错
			printf("erro read \n");
			return false;
		}
		if(!trytimes--){
			printf("read times out!!\n");
			return false;
		}
		count+=ret;
	};
	return true;
}

bool loopWrite(int fd,char *buf, int size){
	int ret =0;
	int count =0;
	int trytimes = 50;//重复的次数。
	while(count < size){
		ret = writeSocket(fd,buf+count,size-count,NULL);
		if(ret <= 0){
			//写出错
			printf("erro write\n");
			return false;
		}
		if(!trytimes--){
			printf("write times out!!\n");
			return false;
		}
		count+=ret;
	};
	return true;
}


#define SOCKET_FILE_PATH "/data/DEBUG_SERVER"
int main (int argc, char *argv[]){
	struct sockaddr_un address;
	int sockfd;
	int len;
	int result;

	/*创建socket,AF_UNIX通信协议,SOCK_STREAM数据方式*/
	if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
	perror ("socket");
	exit (EXIT_FAILURE);
	}
	 
	address.sun_family = AF_UNIX;
	strcpy (address.sun_path, SOCKET_FILE_PATH);
	len = sizeof (address);
	 
	/*向服务器发送连接请求*/
	result = connect (sockfd, (struct sockaddr *)&address, len);
	if (result == -1) {
	printf ("ensure the server is up SOCEKT_FILE:%s\n",SOCKET_FILE_PATH);
	perror ("connect");
	exit (EXIT_FAILURE);
	}


	while(1){
		struct s_cmd cmd={0};
		char *pBuffer = (char*)&cmd;
		printf(">>>>>>>>>>>>>>>>>>input:type,intdata0,sdata\n");
		scanf("%d,%d,%s",&cmd.type,&cmd.i_data0,cmd.s_data);
		//清空之前的缓冲区,不然 会把上一次残余的当做输入
		//setbuf(stdin,NULL);
		unsigned char getBuff;
		while(getBuff=getchar()!='\n' && getBuff!=EOF);
		
		//printf(">>>>>>>>type:%c data0:%d s_data:%s\n",cmd.type,cmd.i_data0,cmd.s_data);
		loopWrite(sockfd,pBuffer,sizeof(struct s_cmd));
		if(cmd.type==2){
			loopRead(sockfd,pBuffer,sizeof(struct s_cmd));
			printf("get result [type:%d,c_data:%c,idata:%d,%d,s_data:%s]\n",cmd.type,cmd.c_data,cmd.i_data0,cmd.i_data1,cmd.s_data);
		}
	}
	close (sockfd);
	return 0;
}
#Android.mk  使用ndk编译,可以先建一个jni目录,然后把这几个文件都拷贝到jni目录下,进jni目录执行ndk-build
LOCAL_SRC_FILES := client.cpp

LOCAL_LDFLAGS += -pie -fPIE
include $(BUILD_EXECUTABLE)


include $(CLEAR_VARS)
LOCAL_MODULE := debug_server
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := server.cpp

LOCAL_LDFLAGS += -pie -fPIE
#LOCAL_SHARED_LIBERAYRS:= libpthread
include $(BUILD_EXECUTABLE)

在android设备上运行,(需要root权限和 setenforce 0)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值