NDK开发汇总
APP保活:设置监听,当应用服务被停止后,重新唤醒应用服务
利用socket机制,监听 app主进程被干掉
a)、创建ServerSocket对象绑定监听端口。
b)、通过accept()方法监听客户端的请求。
c)、建立连接后,通过输入输出流读取客户端发送的请求信息。
d)、通过输出流向客户端发送请求信息。
e)、关闭相关资源。
类似的Java服务端
ServerSocket server=new ServerSocket(5209);
socket=server.accept();
while(1){
//读取空内容
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
line=br.readLine();
}
socket.close(); //关闭Socket
server.close(); //关闭ServerSocket
类似java的获取输入流,并读取服务器端的响应信息
Socket socket = new Socket("192.168.1.115", 5209);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
socket.close(); // 关闭Socket
int socket(int protofamily, int type, int protocol);//返回sockfd
socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字, 而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
protofamily:即协议域,又称为协议族(family)。常用的协议族有:
AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,
type:指定socket类型。
常用的socket类型SOCK_STREAM IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,
它们分别对应 流协议,TCP传输协议、UDP传输协议
、 STCP传输协议、TIPC传输协议
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
#include
#include
#include "native-lib.h"
int m_child;
int m_parent = -1;
const char * user_id;
const char *PATH = "/data/data/com.dongnao.socketprocess/my.sock";
extern "C"{
JNIEXPORT void JNICALL
Java_com_dongnao_socketprocess_Wathcer_createWatcher(JNIEnv *env, jobject instance, jstring userId) {
user_id = (const char *) env->GetStringChars(userId, 0);
create_child();
}
JNIEXPORT void JNICALL
Java_com_dongnao_socketprocess_Wathcer_connectToMonitor(JNIEnv *env, jobject instance) {
// 子进程1 父进程2
int sockfd;
struct sockaddr_un addr;
while (1) {
LOGE("客户端 父进程开始连接");
sockfd=socket(AF_LOCAL, SOCK_STREAM, 0);
if (sockfd < 0) {
return;
}
memset(&addr, 0, sizeof(sockaddr_un));
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, PATH);
if (connect(sockfd, (const sockaddr *) &addr, sizeof(addr)) < 0) {
LOGE("连接失败 休眠");
// 连接失败
close(sockfd);
sleep(1);
// 再来继续下一次尝试
continue;
}
// 连接成功
m_parent = sockfd;
LOGE("连接成功 父进程跳出循环");
break;
}
}
}
void create_child() {
//
pid_t pid = fork();
//
if (pid < 0) {
} else if (pid > 0) {
//父进程
} else if (pid == 0){
LOGE("子进程开启 ");
// 守护进程
child_do_work();
}
}
void child_do_work() {
// 守护进程
// 1 建立socket服务
// 2读取消息
if(child_create_channel()) {
child_listen_msg();
}
}
void child_listen_msg() {
fd_set rfds;
while (1) {
//清空端口号
FD_ZERO(&rfds);
FD_SET(m_child,&rfds);
// 设置超时时间
struct timeval timeout={3,0};
int r=select(m_child + 1, &rfds, NULL, NULL, &timeout);
LOGE("读取消息前 %d ",r);
if (r > 0) {
char pkg[256] = {0};
// 确保读到的内容是制定的端口号
if (FD_ISSET(m_child, &rfds)) {
// 阻塞式函数 客户端写到内容 apk进程 没有进行任何写入 连接
int result = read(m_child, pkg, sizeof(pkg));
// 读到内容的唯一方式 是客户端断开
LOGE("重启父进程 %d ",result);
LOGE("读到信息 %d userid %d ",result,user_id);
execlp("am", "am", "startservice", "--user",user_id,
"com.dongnao.socketprocess/com.dongnao.socketprocess.ProcessService", (char*)NULL);
break;
}
}
}
}
int child_create_channel() {
// 创建socket listenfd 对象
int listenfd=socket(AF_LOCAL, SOCK_STREAM, 0);
// 取消之前进程文件连接
unlink(PATH);
struct sockaddr_un addr;
// 清空内存
memset(&addr, 0, sizeof(sockaddr_un));
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, PATH);
int connfd=0;
LOGE("绑定端口号");
if(bind(listenfd, (const sockaddr *) &addr, sizeof(addr))<0) {
LOGE("绑定错误");
return 0;
}
listen(listenfd, 5);
while (1) {
LOGE("子进程循环等待连接 %d ",m_child);
// 不断接受客户端请求的数据
// 等待 客户端连接 accept阻塞式函数
if ((connfd = accept(listenfd, NULL, NULL)) < 0) {
if (errno == EINTR) {
continue;
} else{
LOGE("读取错误");
return 0;
}
}
// apk 进程连接上了
m_child = connfd;
LOGE("apk 父进程连接上了 %d ",m_child);
break;
}
LOGE("返回成功");
return 1;
}
Socket进程守护.zip