ndk開發(fā)—用socket實現(xiàn)雙進程守護

前篇

首先我們需要了解一下socket的通信原理,大家百度就可以找到這張圖片


socket原理.jpg
  • java實現(xiàn)socket通信
    首先服務(wù)器端
 ServerSocket server = new ServerSocket(8081);
        try {
            Socket client = server.accept();
            try {
                BufferedReader input =
                        new BufferedReader(new InputStreamReader(client.getInputStream()));
                boolean flag = true;
                int count = 1;
 
                while (flag) {
                    System.out.println(連接的第 + count + 次!);
                    count++;
                }
            } finally {
                client.close();
            }
             
        } finally {
            server.close();
        }
    }

然后客戶端

 Socket client = new Socket(127.0.0.1, 8081);

幾個重要方法

  • 1._socket函數(shù):對應(yīng)于普通文件的打開操作
int socket(int __af, int __type, int __protocol);

1.__af:即協(xié)議域缩滨,又稱為協(xié)議族(family)兼搏。常用的協(xié)議族有芹助,AF_INET励翼、AF_INET6缚去、AF_LOCAL(或稱AF_UNIX路克,Unix域socket),AF_ROUTE等
2.__type:指定socket類型樟结。常用的socket類型有,SOCK_STREAM精算、SOCK_DGRAM瓢宦、SOCK_RAW、SOCK_PACKET灰羽、SOCK_SEQPACKET等等
3. __protocol:protocol:故名思意驮履,就是指定協(xié)議。常用的協(xié)議有廉嚼,IPPROTO_TCP玫镐、IPPTOTO_UDP、IPPROTO_SCTP怠噪、IPPROTO_TIPC等恐似,它們分別對應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議傍念、STCP傳輸協(xié)議矫夷、TIPC傳輸協(xié)議

  • 2.bind函數(shù)
_socketcall int bind(int __fd, const struct sockaddr* __addr, socklen_t __addr_length);

__fd:上面第一步創(chuàng)建得到的返回值
__addr:指向要綁定給__fd的協(xié)議地址
__addr_lenght:對應(yīng)的是地址的長度

  • 3.listen()、connect()函數(shù)
    listen函數(shù)將socket變?yōu)楸粍宇愋偷谋锘保却蛻舻倪B接請求
    客戶端通過調(diào)用connect函數(shù)來建立與TCP服務(wù)器的連接

  • 4.accept()函數(shù)
    監(jiān)聽客戶端發(fā)送的請求双藕,其方法會返回一個返回值代表全新的socket描述詞,就是第一步返回值fd一個意思

__socketcall int accept(int __fd, struct sockaddr* __addr, socklen_t* __addr_length);

__addr:代表返回客戶端的協(xié)議地址
__addr_length參數(shù):為協(xié)議地址的長度

  • 5.read函數(shù)
ssize_t read(int __fd, void* __buf, size_t __count) __overloadable
    __RENAME_CLANG(read);

__fd:accept返回成功后的返回值socket描述詞

  • 6.execlp用一個新的進程映像替換當前進程映像

直接貼代碼

#include <sys/select.h>
#include <unistd.h>
#include <sys/socket.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <android/log.h>
#include <sys/types.h>
#include <sys/un.h>
#include <error.h>
#include <stdlib.h>
#include <linux/signal.h>
#include <unistd.h>



void child_do_work();
int child_create_channel();
void child_listen_msg();
//com.peakmain.mall.ndk 自己的包名 peakmain.sock自己起個名字秦陋,阿貓阿狗都可以
const char *PATH = "/data/data/com.peakmain.mall.ndk/peakmain.sock";
int childfd;
const char *userId;


/**
 * 服務(wù)端讀取信息
 * 客戶端
 */
int child_create_channel() {
    //int __af 協(xié)議域蔓彩,又稱協(xié)議族 常用的有 AF_INET 和 AF_INET6
    //int __type 為數(shù)據(jù)傳輸方式/套接字類型,常用的有 SOCK_STREAM(流格式套接字/面向連接的套接字) 和 SOCK_DGRAM(數(shù)據(jù)報套接字/無連接的套接字)
    // int __protocol 常用的有 IPPROTO_TCP 和 IPPTOTO_UDP驳概,分別表示 TCP 傳輸協(xié)議和 UDP 傳輸協(xié)議
    int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    struct sockaddr_un addr;
    unlink(PATH);
    //清空內(nèi)存
    memset(&addr, 0, sizeof(sockaddr_un));
    addr.sun_family = AF_LOCAL;
    strcpy(addr.sun_path, PATH);
    int connfd;
    if (bind(fd, (const sockaddr *) &addr, sizeof(sockaddr_un)) < 0) {
        LOGE("綁定錯誤");
        return 0;
    }
    LOGE("綁定成功");
    //最多同時連接5個
    listen(fd, 5);


    //while 保證宿主連接成功
    while (1) {
        //返回值 客戶端的地址 //阻塞函數(shù)
        if ((connfd = accept(fd, NULL, NULL)) < 0) {
            if (errno == EINTR) {
                continue;
            } else {
                LOGE("讀取錯誤");
                return 0;
            }
        }


        childfd = connfd;
        LOGE("apk 父進程連接上 %d", childfd);
        break;
    }
    return 1;
}

/**
 * 創(chuàng)建服務(wù)端socket
 * 讀取
 */
void child_listen_msg() {
    fd_set rfds;
    //時間  3秒
    struct timeval timeout = {3, 0};
    while (1) {
        //清空內(nèi)容
        FD_ZERO(&rfds);
        //重置
        FD_SET(childfd, &rfds);
        //選擇范圍 一般+1
        int range = select(childfd + 1, &rfds, NULL, NULL, &timeout);
        if (range > 0) {
            char pkg[256] = {0};
            //保證讀到的信息是 指定apk客戶端
            if (FD_ISSET(childfd, &rfds)) {
                int result = read(childfd, pkg, sizeof(pkg));
                //開啟服務(wù)
                //com.peakmain.mall.ndk.ProcessService   自己的服務(wù)全名
                execlp("am", "am", "startservice", "--user", userId,
                       "com.peakmain.mall.ndk.ProcessService", NULL);
                break;
            }
        }
    }
}

void child_do_work() {
    //創(chuàng)建和開啟socket 服務(wù)端
    if (child_create_channel()) {
        child_listen_msg();
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_peakmain_mall_ndk_Watcher_createWathcher(JNIEnv *env, jobject instance, jstring userId_) {
    userId = env->GetStringUTFChars(userId_, 0);
    //開雙進程
    pid_t pid = fork();
    LOGE("pid是%d",pid);
    if (pid < 0) {
        //失敗
    } else if (pid == 0) {
        //子進程 守護進程
        child_do_work();
    } else if (pid > 0) {
        //父進程不做處理
    }

    env->ReleaseStringUTFChars(userId_, userId);
}
//客戶端
extern "C"
JNIEXPORT void JNICALL
Java_com_peakmain_mall_ndk_Watcher_connectMonitor(JNIEnv *env, jobject instance) {
    int socked;
    while (1) {
        socked = socket(AF_LOCAL, SOCK_STREAM, 0);
        if (socked < 0) {
            LOGE("客戶端連接失敗0");
            return;
        }
        struct sockaddr_un addr;
        //清空內(nèi)存
        memset(&addr, 0, sizeof(sockaddr));
        addr.sun_family = AF_LOCAL;
        strcpy(addr.sun_path, PATH);

        if (connect(socked, (sockaddr *) &addr, sizeof(sockaddr_un)) < 0) {
            LOGE("客戶端連接失敗1");
            close(socked);
            sleep(1);
            //在來下一次嘗試連接直到成功為止
            continue;
        }
        LOGE("客戶端連接成功");
        break;
    }

}

使用service的oncreate方法

 Watcher watcher=new Watcher();
        watcher.createWathcher(String.valueOf(Process.myUid()));
        watcher.connectMonitor();
        Timer timer=new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                Log.d("TAG","服務(wù)開啟"+i);
                i++;
            }
        },0,3*1000);

大家再做的時候去結(jié)合socket圖去做赤嚼,然后根據(jù)圖可以找到相應(yīng)的方法,整體還是不難的顺又。圖片中Recv其實可以理解為Read,Send理解為write

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末更卒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子稚照,更是在濱河造成了極大的恐慌蹂空,老刑警劉巖俯萌,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異上枕,居然都是意外死亡咐熙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門辨萍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棋恼,“玉大人,你說我怎么就攤上這事锈玉∽ζ” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵拉背,是天一觀的道長师崎。 經(jīng)常有香客問我,道長椅棺,這世上最難降的妖魔是什么犁罩? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮两疚,結(jié)果婚禮上昼汗,老公的妹妹穿的比我還像新娘。我一直安慰自己鬼雀,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布蛙吏。 她就那樣靜靜地躺著源哩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸦做。 梳的紋絲不亂的頭發(fā)上励烦,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音泼诱,去河邊找鬼坛掠。 笑死,一個胖子當著我的面吹牛治筒,可吹牛的內(nèi)容都是我干的屉栓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耸袜,長吁一口氣:“原來是場噩夢啊……” “哼友多!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起堤框,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤域滥,失蹤者是張志新(化名)和其女友劉穎纵柿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體启绰,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡昂儒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了委可。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渊跋。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖撤缴,靈堂內(nèi)的尸體忽然破棺而出刹枉,到底是詐尸還是另有隱情,我是刑警寧澤屈呕,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布微宝,位于F島的核電站,受9級特大地震影響虎眨,放射性物質(zhì)發(fā)生泄漏蟋软。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一嗽桩、第九天 我趴在偏房一處隱蔽的房頂上張望岳守。 院中可真熱鬧,春花似錦碌冶、人聲如沸湿痢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽譬重。三九已至,卻和暖如春罐氨,著一層夾襖步出監(jiān)牢的瞬間臀规,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工栅隐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留塔嬉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓租悄,卻偏偏與公主長得像谨究,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子恰矩,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 大綱 一.Socket簡介 二.BSD Socket編程準備 1.地址 2.端口 3.網(wǎng)絡(luò)字節(jié)序 4.半相關(guān)與全相...
    VD2012閱讀 2,344評論 0 5
  • 鏈接:https://blog.csdn.net/qq_28865297/article/details/7112...
    wvqusrtg閱讀 845評論 0 7
  • 網(wǎng)絡(luò)模型 物理層 物理層表示的是比特流傳輸记盒,通常包括串口/COM口、并行/LPT口外傅、USB纪吮、網(wǎng)線接口俩檬、電話線接口;...
    秋風弄影閱讀 715評論 0 2
  • socket通信原理 socket又被叫做套接字,它就像連接到兩端的插座孔一樣,通過建立管道碾盟,將兩個不同的進程之間...
    jiodg45閱讀 1,140評論 0 1
  • 3月21日 星期三 晴 親子日記第105天 今天女兒要看我的日記棚辽,我告訴她一直沒寫,女兒鄭重其事的說:“明日復(fù)明日...
    涓涓流水_672f閱讀 106評論 0 2