导航:首页 > 源码编译 > strerror源码

strerror源码

发布时间:2024-05-08 14:28:52

⑴ 如何对自身应用进行卸载监听

前段时间有个同事问我android应用在卸载以后,如何能够通知一下服务器,让用户填写一下卸载的原因,以求为将来的应用修改积累数据。当时他是有段源代码的,但是有点小问题,我只是帮他定位一下了代码的问题,具体细节没有研究。又加上最近工作比较繁忙,所以就放下来了,今天稍微有点空,就自己做了一个应用demo,告知一下诸位在android中如何做到监听自身应用被卸载了。

一 效果演示

打开应用效果图:

图1

点击卸载后提示,如下图:

图2

然后退出应用,卸载程序,会发现当应用被卸载以后,会弹出调用浏览器的提示,这里随便放了一个搜狐浏览页面,在自己的应用中应该调用的一般都是调查页面。如下图:

图3

ok,效果前面已经演示了,现在需要讨论一下其具体实现了。
首先,通过adb shell进入手机,然后第一次进入应用,,像图1一样,不点击按钮,通过 ps | busybox grep ubuntu 看这个应用的进程信息,如下图:

这个时候只有
u0_a108 2953 124 490956 47792 ffffffff 40052a40 S com.example.ubuntuforandroid
2953 这一个进程

点击 卸载后提示 按钮再次,执行刚才执行的ps命令,发现已经有两个进程了如下图:

其实新产生的进程是通过程序调用jni接口

public static native int Reguninstall(String path,String url);

这个接口fork了一个进程,而新fork的进程负责监听本应用是否被卸载了

源码分析

java层的代码如下,很简单,就是调用一下jni接口

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initInjectFunction("testfile"); test = (TextView)this.findViewById(R.id.testview); test.setText("点击卸载后提示按钮,你的应用在卸载以后会调用浏览器,然后调用你需要的页面。"); btn = (Button)this.findViewById(R.id.testbtn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub String directory = MainActivity.this.getFilesDir().getAbsolutePath(); String url = "http://www.sohu.com/"; JniExec.Reguninstall(directory,url); test.setText("现在可以退出应用,然后卸载应用,看看是否有效果"); } }); }

一目了然,不用多言了

现在就分析
package com.example.ubuntuforandroid; public class JniExec { static { System.loadLibrary("uninstall"); } public static native int Reguninstall(String path,String url); }
Reguninstall 这个jni接口里面做了什么事情,能够达到监听本身应用卸载的效果。

native代码分析

jint Java_com_example_ubuntuforandroid_JniExec_Reguninstall(JNIEnv* env, jobject thiz, jstring path, jstring url) { LOGI("Java_com_example_ubuntuforandroid_JniExec_Reguninstall"); char *listenpath = (char*) (*env)->GetStringUTFChars(env,path, 0); char *jumpurl = (char*) (*env)->GetStringUTFChars(env,url, 0); LOGI("notify path is %s",listenpath); LOGI("jumpurl is %s",jumpurl); pid_t pid; pid = fork(); if(pid == 0) { //子进程 inotify_main(listenpath,jumpurl); } //父进程不阻塞调用 waitpid ok 子进程变成了孤儿进程,被init进程收养了 pid = waitpid(-1,0,1); LOGI("father bye bye"); return 0; }

这个接口里面最关键的是调用了 inotify_main 这个函数。如果看这段代码比较费力的话,建议先弄清楚linux 下的fork机制,搞清楚 孤儿进程 僵尸进程这些如何产生的情况。

下面看 inotify_main 这个函数
void inotify_main(char *path,char *url) { struct pollfd poll_list[2]; poll_list[0].fd = inotify_init(); poll_list[0].events = POLLIN; int wd = inotify_add_watch(poll_list[0].fd, path, IN_DELETE | IN_CREATE); if(wd < 0) { fprintf(stderr, "could not add watch for %s, %s\n", path, strerror(errno)); return ; } int retval; while(1) { retval = poll(poll_list,(unsigned long)1,-1); /* retval 总是大于0或为-1,因为我们在阻塞中工作 */ LOGI("retval = %d\n",retval); if(retval < 0) { fprintf(stderr,"poll错误: %s/n",strerror(errno)); return; } if((poll_list[0].revents & POLLIN) == POLLIN) { LOGI("poll_list[0].revents&POLLIN\n"); inotify_handle(poll_list[0].fd,url); } } inotify_rm_watch(poll_list[0].fd,wd); }

⑵ C语言对网络的操作和C程序的界面问题!

------------------
你学习C语言的网络编程,我建议你到LINUX下去学
给你一个例子程序是一个局域网聊天服务器
------------------
#define SAY_HELLO 0 /*发送欢迎信息*/

#define SEND_MESSAGE 1 /*转发聊天信息*/

#define CHANGE_NAME 2 /*更改用户名*/

#define REFLESH_LIST 3 /*刷新用户名列表*/

#define CLIENT_LEFT 4 /*客户端离开*/

#define CLIENT_COME 5 /*客户加入*/

#define SEND_RECV_FILE 6 /*发送接收文件*/

#define END_OF_FILE 7 /*文件发送结束标记*/

#define FILE_BLOCK 1024 /*读取文件的块大小*/

#define MAX_CHATER 100 /*服务器最大同时容纳人数*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <netdb.h>

#include <fcntl.h>

#include <bits/time.h>

/*服务端发送欢迎信息*/

struct Message0{

int Func_number; /*功能号: 此处取0 SAY_HELLO

1------表示转发信息

2------表示转发更名通知

3------表示传送当前用户列表

4------表示客户端离开

5------表示客户加入

6------表示发送和接收文件

*/

char msg[50]; /* 欢迎信息 */

char username[50]; /* 服务器端生成的用户名称 */

};

/*服务器端与客户端信息转发数据结构*/

struct Message1{

int Func_number; /*功能号: 此处取1 SEND_MESSAGE

1------表示转发信息

2------表示转发更名通知

3------表示传送当前用户列表

4------表示客户端离开

5------表示客户加入

6------表示发送和接收文件

*/

char msg[201]; /* 转发的信息 */

char send_user_name [50]; /* 发送数据的用户呢称 */

char recv_user_name [50]; /* 接收数据的用户名称 */

};

/*服务器端转发更名通知*/

struct Message2{

int Func_number; /*功能号: 此处取2 CHANGE_NAME

1------表示转发信息

2------表示转发更名通知

3------表示传送当前用户列表

4------表示客户端离开

5------表示客户加入

6------表示发送和接收文件

*/

char oldname[50]; /* 转发更名通知信息 */

char newname[50];

};

/*服务器保存当前所有用户列表的数据结构*/

struct User{

char user_name[50]; /* 用户呢称 */

char user_address[15]; /* 该用户IP地址 */

};

/*服务器转发在线用户列表*/

struct Message3{

int Func_number; /*功能号: 此处取3 REFLESH_LIST

1------表示转发信息

2------表示转发更名通知

3------表示传送当前用户列表

4------表示客户端离开

5------表示客户加入

6------表示发送和接收文件

*/

int current_number; /* 当前在线人数 */

struct User user_list[MAX_CHATER];

/* 服务端维护的用户列表 */

};

/*客户端发出的离开信息*/

struct Message4{

int Func_number; /*功能号: 此处取4 CLIENT_LEFT

1------表示转发信息

2------表示转发更名通知

3------表示传送当前用户列表

4------表示客户端离开

5------表示客户加入

6------表示发送和接收文件

*/

char client_name[50]; /* 离开的客户端名称 */

};

/*新客户登录提示*/

struct Message5{

int Func_number; /*功能号: 此处取5 CLIENT_COME

1------表示转发信息

2------表示转发更名通知

3------表示传送当前用户列表

4------表示客户端离开

5------表示客户加入

6------表示发送和接收文件

*/

char username[50]; /*新客户名称*/

};

/*读取文件块大小*/

struct datablock{

unsigned char block[FILE_BLOCK]; /*读取文件的块大小*/

};

/*发送接收文件的数据结构*/

struct Message6{

int Func_number; /*功能号: 此处取6 SEND_RECV_FILE

1------表示转发信息

2------表示转发更名通知

3------表示传送当前用户列表

4------表示客户端离开

5------表示客户加入

6------表示发送和接收文件

*/

struct datablock msg; /*文件数据块*/

char file_name[512]; /*文件名*/

int end_flag; /*文件结束标记

0------包含有文件信息

1------表示请求发送文件,要求建立连接

2------表示请求成功(对方同意接收文件)

3------表示请求不成功(对方不同意接收文件)

7------(END_OF_FILE)表示文件传送完成

*/

char send_user_name [50]; /* 发送数据的用户呢称 */

char recv_user_name [50]; /* 接收数据的用户名称 */

};

/*

* Netchat 1.0 Server

*/

#include "head.h"

int main(int argc,char ** argv)

{

int listen_fd; /*define var for listen*/

int accept_fd[MAX_CHATER]; /*define fd for accept*/

int port_number; /*define port number*/

int total_connect_number; /*define var save total number*/

int i,sockaddr_in_size; /*define var for help run*/

struct sockaddr_in server_addr; /*define server addr*/

struct sockaddr_in client_addr; /*define client addr*/

struct Message3 allusers; /*define var to save user list*/

struct Message0 wellcome; /*define hello message*/

struct timeval wait_time; /*define time*/

pid_t pid;

fd_set read_fdset; /*define var for select*/

int max_fd; /*define var to save max fd*/

sockaddr_in_size=sizeof(struct sockaddr_in);

pid=-1;

/*init user list*/

memset(&allusers,0x0,sizeof(allusers));

allusers.Func_number=REFLESH_LIST;

memset(&wellcome,0x0,sizeof(wellcome));

wellcome.Func_number=SAY_HELLO;

/*send hello message*/

sprintf(wellcome.msg,"%s","Hello Wellcome to NETCHAT 1.0");

/*init time*/

wait_time.tv_sec=1;

wait_time.tv_usec=0;

/*check main arg*/

if(argc!=2)

{

fprintf(stderr,"\n[Error]\tWrong format,usage : %s [portnumber] to start server.\n",argv[0]);

exit(1);

}

if((port_number=atoi(argv[1]))<0)

{

fprintf(stderr,"\n[Error]\tWrong port number, the portnumber must bigger than zero."

"(suggest bigger than 5000)\n");

exit(1);

}

/*run server socket*/

if( (listen_fd=socket(AF_INET,SOCK_STREAM,0))==-1 )

{

fprintf(stderr,"\n[Error]\tSocket error:%s\n",strerror(errno));

exit(1);

}

/*fill server address*/

bzero(&server_addr,sizeof(struct sockaddr_in));

server_addr.sin_family=AF_INET;

server_addr.sin_port=htons(port_number);

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

/*bind socket to listen_fd*/

if(bind(listen_fd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in))==-1)

{

fprintf(stderr,"\n[Error]\tBind error:%s\n",strerror(errno));

exit(1);

}

/*listen...*/

listen(listen_fd,MAX_CHATER);

fprintf(stderr,"\n-->The server had started successfully<--");

/*init accept_fd*/

memset(accept_fd,-1,MAX_CHATER);

max_fd=-1;

total_connect_number=0;

/*init userlist the total number*/

allusers.current_number=total_connect_number;

/*set listen_fd nonblock*/

fcntl(listen_fd,F_SETFL,O_NONBLOCK);

while(1)

{

int i;

char tmp_command[128];

fflush(stdout);

/*re-set read_fdset*/

FD_ZERO(&read_fdset);

/*add listen_fd to the read_fdset*/

FD_SET(listen_fd,&read_fdset);

if(listen_fd>max_fd)

max_fd=listen_fd;

/*add keybord input to read_fdset*/

FD_SET(0,&read_fdset);

/* readd all acceptfd to fdsett*/

for(i=0;i<total_connect_number;i++)

{

FD_SET(accept_fd[i],&read_fdset);

if(accept_fd[i]>max_fd)

max_fd=accept_fd[i];

}

/* wait_time.tv_sec=1;

wait_time.tv_usec=0;

*/

fprintf(stderr,"\n(Type \"exit\" and ENTER to exit)Enter command ->");

fflush(stdout);

/*do select*/

/* select(max_fd+1,&read_fdset,NULL,NULL,&wait_time); */

select(max_fd+1,&read_fdset,NULL,NULL,NULL);

if(FD_ISSET(0,&read_fdset))

{

char tmp_char;

int k=0;

tmp_char=getchar();

while(tmp_char!='\n')

{

tmp_command[k]=tmp_char;

k++;

tmp_char=getchar();

}

}

if(strcmp(tmp_command,"exit")==0)

goto exit_come;

if(FD_ISSET(listen_fd,&read_fdset))

{

/*accept a new connect*/

accept_fd[total_connect_number]=accept(listen_fd,

(struct sockaddr *)(&client_addr),&sockaddr_in_size);

/*add the new user to read_fdset*/

if(accept_fd[total_connect_number]!=-1)

{

int k;

time_t timep; /*define the second tmp*/

struct Message5 new_user;

memset(&new_user,0,sizeof(new_user));

new_user.Func_number=CLIENT_COME;

time(&timep);

/*become the username*/

sprintf(wellcome.username,"%s%d","chater",timep%10000);

strcpy(new_user.username,wellcome.username);

fprintf(stderr,"\n[TIP]\tA user connected");

send(accept_fd[total_connect_number],&wellcome,sizeof(wellcome),0);

for(k=0;k<total_connect_number;k++)

{

/*send wellcome message*/

send(accept_fd[k],&new_user,sizeof(new_user),0);

}

/*add the new connect fd to read_fdset*/

FD_SET(accept_fd[total_connect_number],&read_fdset);

/*re-value the max_fd*/

if(accept_fd[total_connect_number]>max_fd)

{

max_fd=accept_fd[total_connect_number];

}

sprintf( allusers.user_list[total_connect_number].user_name,

"%s",wellcome.username);

sprintf( allusers.user_list[total_connect_number].user_address,

"%s",inet_ntoa(client_addr.sin_addr) );

/*compute the new total number*/

allusers.current_number++;

total_connect_number++;

/*re-init the client address*/

memset(&client_addr,0x0,sizeof(client_addr));

}/*add accept_fd to fd_set end*/

continue;

}/*test new user come end*/

/*test is there are any message come*/

for(i=0;i<total_connect_number;i++)

{

/*if the message come*/

if(FD_ISSET(accept_fd[i],&read_fdset))

{

/*define var to receive the function number*/

int get_Func_number;

/*peek the function number*/

if(recv(accept_fd[i],&get_Func_number,sizeof(int),MSG_PEEK)

==-1)

{

fprintf(stderr,"\n[Error]\tReceive Function number "

"error:%s",strerror(errno));

get_Func_number=-1;

continue;

}

/*error happened ,exit*/

if(get_Func_number<=0)

{

fprintf(stderr,"The Function number is bad:%d\n",get_Func_number);

goto exit_come;

}

/*do by functin number*/

switch(get_Func_number)

{

/*transmit message to others*/

case 1:

{

/*define transmit var*/

struct Message1 get_message;

int j;

fprintf(stderr,"\n[TIP]\tThe get_Funcnumber is:%d",

get_Func_number);

/*receive message*/

if(recv(accept_fd[i],&get_message,

sizeof(get_message),0)==-1)

{

fprintf(stderr,

"\n[Error]\tReceive error:%s",

strerror(errno));

break;

}

/*do transmit*/

for(j=0;j<total_connect_number;j++)

{

send(accept_fd[j],&get_message,sizeof(get_message),0);

}

fprintf(stderr,"\n[TIP]\tTransmit1 (transmit message) message ok.");

break;

}

/*change name*/

case 2:

{

/*define var for change name*/

struct Message2 get_message;

int j;

memset(&get_message,0,sizeof(get_message));

fprintf(stderr,"\n[TIP]\tThe get_Funcnumber is:%d",get_Func_number);

/*receive change name message*/

if(recv(accept_fd[i],&get_message,sizeof(get_message),0)==-1)

{

fprintf(stderr,"\n[Error]\tReceive error:%s",strerror(errno));

break;

}

/*test name*/

for(j=0;j<total_connect_number;j++)

{

if(strcmp(allusers.user_list[j].user_name,get_message.newname)==0)

{

fprintf(stderr,"\n[Error]\tThe name had exist");

memset(get_message.newname,0,sizeof(get_message.newname));

strcpy(get_message.newname,"Error");

send(accept_fd[i],&get_message,sizeof(get_message),0);

fprintf(stderr,"\n[Error]\tChange name error");

goto exit_case_come;

}

}

/*change user list*/

for(j=0;j<total_connect_number;j++)

{

if(strcmp(allusers.user_list[j].user_name,get_message.oldname)==0)

{

memset(allusers.user_list[j].user_name,0,

sizeof(allusers.user_list[j].user_name));

strcpy(allusers.user_list[j].user_name,get_message.newname);

}

}

for(j=0;j<total_connect_number;j++)

{

send(accept_fd[j],&get_message,sizeof(get_message),0);

}

fprintf(stderr,"\n[TIP]\tTransmit2 (change name) message ok.");

break;

}

case 3:

/*transmit user list*/

{

/*define int var for receive function number*/

int get_message;

fprintf(stderr,"\n[TIP]\tThe get_Funcnumber is:%d",

get_Func_number);

/*receive message*/

if(recv(accept_fd[i],&get_message,

sizeof(int),0)==-1)

{

fprintf(stderr,

"\n[Error]\tReceive error:%s",

strerror(errno));

break;

}

fprintf(stderr,"\n[TIP]\tTotal user number is:%d",allusers.current_number);

/*do send user list*/

if(send(accept_fd[i],&allusers,sizeof(allusers),0) == -1)

{

fprintf(stderr,

"\n[Error]\tTransmit3 message error.");

break;

}

else

{

fprintf(stderr,

"\n[TIP]\tTransmit3 (send user list) "

"message ok.");

}

break;

}

/*transmit user left message*/

case 4:

{

/*define var for do*/

struct Message4 get_message;

int j,k;

fprintf(stderr,"\n[TIP]\tThe get_Funcnumber is:%d",get_Func_number);

/*receive message*/

if(recv(accept_fd[i],&get_message,sizeof(get_message),0)==-1)

{

fprintf(stderr,"\n[Error]\tReceive error:%s",strerror(errno));

break;

}

/*delete user from accept_fd[] and userlist[]*/

for(j=0;j<total_connect_number;j++)

{

if(strcmp(allusers.user_list[j].user_name,get_message.client_name)==0)

{

for(k=j;k<total_connect_number-1;k++)

{

allusers.user_list[k]=allusers.user_list[k+1];

}

for(k=j;k<total_connect_number-1;k++)

{

accept_fd[k]=accept_fd[k+1];

}

break;

}

}

total_connect_number--;

allusers.current_number--;

/*send all user the left message*/

for(j=0;j<total_connect_number;j++)

{

send(accept_fd[j],&get_message,sizeof(get_message),0);

}

fprintf(stderr,"\n[TIP]\tTransmit4 (a user had exit) message ok.");

break;

}/*end of case 4*/

/*receive file*/

case 6:

{

struct Message6 get_message;

int j;

fprintf(stderr,"\n[TIP]\tThe get_Funcnumber is:%d",get_Func_number);

memset(&get_message,0,sizeof(get_message));

if(recv(accept_fd[i],&get_message,sizeof(get_message),0)==-1)

{

fprintf(stderr,"\n[Error]\tReceive error:%s",strerror(errno));

break;

}

for(j=0;j<total_connect_number;j++)

{

/*find the dest accept_fd*/

if(strcmp(allusers.user_list[j].user_name,get_message.recv_user_name)==0)

{

break;

}

}

/*transmit the info*/

send(accept_fd[j],&get_message,sizeof(get_message),0);

break;

}

default:

{

fprintf(stderr,"\n[TIP]\tThe get_Funcnumber is:%d\n",get_Func_number);

goto exit_come;

}

exit_case_come:

}/*end of switch*/

}/*end of if*/

}/*end of for*/

}/*end of while*/

exit_come:

close(listen_fd);

exit(0);

}/*end of main*/

阅读全文

与strerror源码相关的资料

热点内容
php提交过滤 浏览:346
豪斯曼检验stata命令 浏览:765
云看地是什么APP 浏览:883
数学指南pdf 浏览:856
phpcurldll64位 浏览:976
程序员脱产一年半 浏览:849
hr招程序员有什么条件 浏览:587
android开源集合 浏览:867
华为云服务器登录密码和账号 浏览:154
中世纪java程序员 浏览:786
什么开发引擎使用python 浏览:176
sh脚本运行命令 浏览:316
广联达加密锁怎么看到期 浏览:173
cad轨迹命令 浏览:980
同事刷到女程序员自媒体视频 浏览:573
校验算法的缺点是什么 浏览:718
PHP商品分类功能实现 浏览:330
php取字符串中间 浏览:432
程序员经常用工具 浏览:837
降服主力指标源码主图 浏览:502