257.Android Studio JNI中login和服务器的交互

java层通过JNI调用c++的代码来向服务器发送用户的登录验证信息,然后c++的再封装相关的json数据通过libcurl库向服务器发送登录验证信息,服务器来返回验证结果,login.cpp上再解析返回来的json结果,将解析的结果返回给java层。这就是Android上同服务器交互的大致流程。

封装Json向服务器发送

json格式

 ====给服务端的协议====
http://ip:port/login [json_data]
{
  username: "gailun",
  password: "123123",
  driver:   "yes"
}

封装Json的代码

//(1)封装一个json字符串
cJSON *root = cJSON_CreateObject();

cJSON_AddStringToObject(root, "username", username);
cJSON_AddStringToObject(root, "password", passwd);
cJSON_AddStringToObject(root, "driver", isDriver);

post_str = cJSON_Print(root);
cJSON_Delete(root);//释放root的空间
root = NULL;

libcurl访问服务器

//(2) 想web服务器 发送http请求 其中post数据 json字符串
//1 设置curl url
curl_easy_setopt(curl, CURLOPT_URL, "http://101.200.190.150:7777/login");
//2 开启post请求开关
curl_easy_setopt(curl, CURLOPT_POST, true);
//3 添加post数据
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_str);

//4 设定一个处理服务器响应的回调函数,deal_response是回调函数
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, deal_response);

//5 给回调函数传递一个形参
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);

//6 向服务器发送请求,等待服务器的响应
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
	__android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:perform ERROR, rescode= [%d]\n",
						res);
	return JNI_FALSE;

}

服务器返回数据,服务器响应的数据是json类型的格式如下

 //成功
{
   result: "ok",
}
//失败
{
   result: "error",
   reason: "why...."
}

接受服务器返回数据代码如下:

//(4) 解析服务器返回的json字符串
root = cJSON_Parse(responseData.data);

cJSON *result = cJSON_GetObjectItem(root, "result");
if(result && strcmp(result->valuestring, "ok") == 0) {
	//登陆成功
	__android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:login succ!!!");
	return JNI_TRUE;

}
else {
	//登陆失败
	cJSON* reason = cJSON_GetObjectItem(root, "reason");
	if (reason) {
		//已知错误
		__android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:login error, reason = %s!!!", reason->valuestring);

	}
	else {
		//未知的错误
		__android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:login error, reason = Unknow!!!");

	}

	return JNI_FALSE;
}

login.cpp代码

//
// Created by Administrator on 2019/10/13.
//

#include "login.h"
#include "cJSON.h"
#include <android/log.h>
#include "curl/curl.h"

//默认服务器返回数据的长度
#define RESPONSE_DATA_LEN 4096

//用来接收服务器一个buffer
typedef struct login_response_data
{
    //构造函数
    login_response_data() {
        //分配空间
        memset(data, 0, RESPONSE_DATA_LEN);
        data_len = 0;
    }

    char data[RESPONSE_DATA_LEN];
    int data_len;

}response_data_t;

//处理从服务器返回的数据ptr,将数据拷贝到arg中
size_t deal_response(void *ptr, size_t n, size_t m, void *arg)
{
    int count = m*n;

    response_data_t *response_data = (response_data_t*)arg;

    memcpy(response_data->data, ptr, count);

    response_data->data_len = count;

    return response_data->data_len;
}

/*
 * Class:     com_ldw_hello_BridgeUtils
 * Method:    login
 * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_com_ldw_hello_BridgeUtils_login
  (JNIEnv * env, jobject obj, jstring jni_username, jstring jni_password, jboolean jni_isdriver)
  {
    const char *username = env->GetStringUTFChars(jni_username, 0);
    const char *passwd = env->GetStringUTFChars(jni_password, 0);
    const char *isDriver = jni_isdriver == JNI_TRUE?"yes":"no";

    char *post_str = NULL;
    CURL* curl = NULL;//初始化一个curl指针
    CURLcode res;//服务器返回的结果
    response_data_t responseData;//专门用来存放从服务器返回的数据

    curl = curl_easy_init();
    if(curl == NULL){
        __android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login: curl init error \n");
        return JNI_FALSE;

    }

    __android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login: username = %s, passwd = %s, isDriver = %s",
                            username, passwd, isDriver);

    //封装一个数据协议
    /*

     ====给服务端的协议====
    http://ip:port/login [json_data]
    {
      username: "gailun",
      password: "123123",
      driver:   "yes"
    }
    *
    *
    * */
    //(1)封装一个json字符串
    cJSON *root = cJSON_CreateObject();

    cJSON_AddStringToObject(root, "username", username);
    cJSON_AddStringToObject(root, "password", passwd);
    cJSON_AddStringToObject(root, "driver", isDriver);

    post_str = cJSON_Print(root);
    cJSON_Delete(root);//释放root的空间
    root = NULL;

    __android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login: post_str = [%s]\n", post_str);
    //(2) 想web服务器 发送http请求 其中post数据 json字符串
    //1 设置curl url
    curl_easy_setopt(curl, CURLOPT_URL, "http://101.200.190.150:7777/login");
    //2 开启post请求开关
    curl_easy_setopt(curl, CURLOPT_POST, true);
    //3 添加post数据
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_str);

    //4 设定一个处理服务器响应的回调函数,deal_response是回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, deal_response);

    //5 给回调函数传递一个形参
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);

    //6 向服务器发送请求,等待服务器的响应
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        __android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:perform ERROR, rescode= [%d]\n",
                            res);
        return JNI_FALSE;

    }
    //(3) 等待服务器的响应 此刻的responseData就是从服务器获取的数据

    /*
     //成功
    {
       result: "ok",
    }
    //失败
    {
       result: "error",
       reason: "why...."
    }
    *
    * */
    //(4) 解析服务器返回的json字符串
    root = cJSON_Parse(responseData.data);

    cJSON *result = cJSON_GetObjectItem(root, "result");
    if(result && strcmp(result->valuestring, "ok") == 0) {
        //登陆成功
        __android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:login succ!!!");
        return JNI_TRUE;

    }
    else {
        //登陆失败
        cJSON* reason = cJSON_GetObjectItem(root, "reason");
        if (reason) {
            //已知错误
            __android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:login error, reason = %s!!!", reason->valuestring);

        }
        else {
            //未知的错误
            __android_log_print(ANDROID_LOG_ERROR,TAG,"JNI-login:login error, reason = Unknow!!!");

        }

        return JNI_FALSE;
    }

    return JNI_TRUE;
  }

服务器代码如下http_server.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>     //for getopt, fork
#include <string.h>     //for strcat
//for struct evkeyvalq
#include <sys/queue.h>
#include <event.h>
//for http
//#include <evhttp.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <event2/http_compat.h>
#include <event2/util.h>
#include <signal.h>
#include <cJSON.h>

#define MYHTTPD_SIGNATURE   "MoCarHttpd v0.1"

//处理模块
void httpd_handler(struct evhttp_request *req, void *arg) {
    char output[2048] = "\0";
    char tmp[1024];

    //获取客户端请求的URI(使用evhttp_request_uri或直接req->uri)
    const char *uri;
    uri = evhttp_request_uri(req);
#if 0
    sprintf(tmp, "uri=%s\n", uri);//  /data?cmd=new...
    strcat(output, tmp);
#endif

    sprintf(tmp, "uri=%s\n", req->uri);
    strcat(output, tmp);

    //decoded uri
    char *decoded_uri;
    decoded_uri = evhttp_decode_uri(uri);
    sprintf(tmp, "decoded_uri=%s\n", decoded_uri);// /data?cmd= newFile ...
    strcat(output, tmp);

    //http://127.0.0.1:8080/username=gailun&passwd=123123

    //解析URI的参数(即GET方法的参数)
    struct evkeyvalq params;//key ---value, key2--- value2//  cmd --- newfile  fromId == 0
    //将URL数据封装成key-value格式,q=value1, s=value2
    evhttp_parse_query(decoded_uri, &params);

    //得到q所对应的value
    sprintf(tmp, "username=%s\n", evhttp_find_header(&params, "username"));
    strcat(output, tmp);
    //得到s所对应的value
    sprintf(tmp, "passwd=%s\n", evhttp_find_header(&params, "passwd"));
    strcat(output, tmp);

    free(decoded_uri);

    //获取POST方法的数据
    char *post_data = (char *) EVBUFFER_DATA(req->input_buffer);
    sprintf(tmp, "post_data=%s\n", post_data);
    strcat(output, tmp);


    /*
       具体的:可以根据GET/POST的参数执行相应操作,然后将结果输出
       ...
     */
    //入库



    /* 输出到客户端 */

    //HTTP header
    evhttp_add_header(req->output_headers, "Server", MYHTTPD_SIGNATURE);
    evhttp_add_header(req->output_headers, "Content-Type", "text/plain; charset=UTF-8");
    evhttp_add_header(req->output_headers, "Connection", "close");

    //输出的内容
    struct evbuffer *buf;
    buf = evbuffer_new();
    evbuffer_add_printf(buf, "It works!\n%s\n", output);

    //将封装好的evbuffer 发送给客户端
    evhttp_send_reply(req, HTTP_OK, "OK", buf);

    evbuffer_free(buf);

}

//处理模块
void login_handler(struct evhttp_request *req, void *arg) {

    printf("got connection ");

    char request_data[4096] = {0};

    //获取POST方法的数据
    size_t post_size = EVBUFFER_LENGTH(req->input_buffer);
    char *post_data = (char *) EVBUFFER_DATA(req->input_buffer);
    memcpy(request_data, post_data, post_size);
    printf("post_data = [%s], len =%ld\n", post_data, post_size);



    char username[256] = {0};
    char password[256] = {0};
    char isDriver[10] = {0};
    /*
       具体的:可以根据GET/POST的参数执行相应操作,然后将结果输出
       ...
     */

    /*

       ====给服务端的协议====
        http://ip:port/login [json_data]
        {
            username: "gailun",
            password: "123123",
            driver:   "yes"
        }
     *
     *
     * */
    cJSON *root = cJSON_Parse(request_data);
    


    cJSON* username_obj = cJSON_GetObjectItem(root, "username");
    strcpy(username, username_obj->valuestring);


    cJSON* password_obj = cJSON_GetObjectItem(root, "password");
    strcpy(password, password_obj->valuestring);

    cJSON* isDriver_obj = cJSON_GetObjectItem(root, "driver");
    strcpy(isDriver, isDriver_obj->valuestring);

    printf("username = %s, password = %s, isDriver = %s\n", username, password, isDriver);
    cJSON_Delete(root);
    printf("----\n");


    //查询数据库 得到查询结果


    //给前段回复一个响应结果
    cJSON*response_root = cJSON_CreateObject();
    
    cJSON_AddStringToObject(response_root, "result", "ok");

    char *response_str = cJSON_Print(response_root);




    /* 输出到客户端 */

    //HTTP header
    evhttp_add_header(req->output_headers, "Server", MYHTTPD_SIGNATURE);
    evhttp_add_header(req->output_headers, "Content-Type", "text/plain; charset=UTF-8");
    evhttp_add_header(req->output_headers, "Connection", "close");

    //输出的内容
    struct evbuffer *buf;
    buf = evbuffer_new();
    evbuffer_add_printf(buf, "%s", response_str);

    //将封装好的evbuffer 发送给客户端
    evhttp_send_reply(req, HTTP_OK, "OK", buf);

    evbuffer_free(buf);

    cJSON_Delete(response_root);
    free(response_str);
}


void show_help() {
    char *help = "http://localhost:8080\n"
        "-l <ip_addr> interface to listen on, default is 0.0.0.0\n"
        "-p <num>     port number to listen on, default is 1984\n"
        "-d           run as a deamon\n"
        "-t <second>  timeout for a http request, default is 120 seconds\n"
        "-h           print this help and exit\n"
        "\n";
    fprintf(stderr,"%s",help);
}

//当向进程发出SIGTERM/SIGHUP/SIGINT/SIGQUIT的时候,终止event的事件侦听循环
void signal_handler(int sig) {
    switch (sig) {
        case SIGTERM:
        case SIGHUP:
        case SIGQUIT:
        case SIGINT:
            event_loopbreak();  //终止侦听event_dispatch()的事件侦听循环,执行之后的代码
            break;
    }
}

int main(int argc, char *argv[]) {
    //自定义信号处理函数
    signal(SIGHUP, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGINT, signal_handler);
    signal(SIGQUIT, signal_handler);

    //默认参数
    char *httpd_option_listen = "0.0.0.0";
    int httpd_option_port = 7777;
    int httpd_option_daemon = 0;
    int httpd_option_timeout = 120; //in seconds

    //获取参数
    int c;
    while ((c = getopt(argc, argv, "l:p:dt:h")) != -1) {
        switch (c) {
            case 'l' :
                httpd_option_listen = optarg;
                break;
            case 'p' :
                httpd_option_port = atoi(optarg);
                break;
            case 'd' :
                httpd_option_daemon = 1;
                break;
            case 't' :
                httpd_option_timeout = atoi(optarg);
                break;
            case 'h' :
            default :
                show_help();
                exit(EXIT_SUCCESS);
        }
    }

    //判断是否设置了-d,以daemon运行
    if (httpd_option_daemon) {
        pid_t pid;
        pid = fork();
        if (pid < 0) {
            perror("fork failed");
            exit(EXIT_FAILURE);
        }
        if (pid > 0) {
            //生成子进程成功,退出父进程
            exit(EXIT_SUCCESS);
        }
    }


    /* 使用libevent创建HTTP Server */

    //初始化event API
    event_init();

    //创建一个http server
    struct evhttp *httpd;

    httpd = evhttp_start(httpd_option_listen, httpd_option_port);

    evhttp_set_timeout(httpd, httpd_option_timeout);

    //也可以为特定的URI指定callback
    evhttp_set_cb(httpd, "/", httpd_handler, NULL);
    evhttp_set_cb(httpd, "/login", login_handler, NULL);

    //循环处理events
    event_dispatch();

    evhttp_free(httpd);

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值