[Android]数据服务器开发

本文介绍了Android数据服务器的开发过程,涉及服务器数据处理、缓存操作、持久化数据库入库及数据库API封装。主要函数包括deal_cache.c中的缓存操作如设置生命周期、字符串、哈希等,以及persistent.c中的持久化数据库操作,如用户表的插入和查询。文章还讨论了服务器为何只使用两个URL,并提及协议和URL设计对于APP开发的重要性。
摘要由CSDN通过智能技术生成

server-data

在这里插入图片描述

https-server.c

搭建数据服务器时只做了两个处理,设置了两个专属URL和对应的对调函数

	evhttp_set_cb(http, "/persistent", persistent_store_cb, NULL);
    evhttp_set_cb(http, "/cache", cache_store_cb, NULL);
	unsigned short serverPort = COMMON_HTTPS_PORT;
	
	/* Instead of casting between these types, create a union with all of them,
	 * to avoid -Wstrict-aliasing warnings. */
	typedef union
	{ 
	    struct sockaddr_storage ss;
	    struct sockaddr sa;
	    struct sockaddr_in in;
	    struct sockaddr_in6 i6;
	} sock_hop;
	
	
	
	/**
	 * This callback is responsible for creating a new SSL connection
	 * and wrapping it in an OpenSSL bufferevent.  This is the way
	 * we implement an https server instead of a plain old http server.
	 */
	static struct bufferevent* bevcb (struct event_base *base, void *arg)
	{ 
	    struct bufferevent* r;
	    SSL_CTX *ctx = (SSL_CTX *) arg;
	
	    r = bufferevent_openssl_socket_new (base,
	            -1,
	            SSL_new (ctx),
	            BUFFEREVENT_SSL_ACCEPTING,
	            BEV_OPT_CLOSE_ON_FREE);
	    return r;
	}
	
	static void server_setup_certs (SSL_CTX *ctx,
	        const char *certificate_chain,
	        const char *private_key)
	{ 
	    info_report ("Loading certificate chain from '%s'\n"
	            "and private key from '%s'\n",
	            certificate_chain, private_key);
	
	    if (1 != SSL_CTX_use_certificate_chain_file (ctx, certificate_chain))
	        die_most_horribly_from_openssl_error ("SSL_CTX_use_certificate_chain_file");
	
	    if (1 != SSL_CTX_use_PrivateKey_file (ctx, private_key, SSL_FILETYPE_PEM))
	        die_most_horribly_from_openssl_error ("SSL_CTX_use_PrivateKey_file");
	
	    if (1 != SSL_CTX_check_private_key (ctx))
	        die_most_horribly_from_openssl_error ("SSL_CTX_check_private_key");
	}
	
	static int serve_some_http (void)
	{ 
	    struct event_base *base;
	    struct evhttp *http;
	    struct evhttp_bound_socket *handle;
	
	    
	    base = event_base_new ();
	    if (! base)
	    { 
	        fprintf (stderr, "Couldn't create an event_base: exiting\n");
	        return 1;
	    }
	
	    /* 创建一个 evhttp 句柄,去处理用户端的requests请求 */
	    http = evhttp_new (base);
	    if (! http)
	    { fprintf (stderr, "couldn't create evhttp. Exiting.\n");
	        return 1;
	    }
	
	    /* 创建SSL上下文环境 ,可以理解为 SSL句柄 */
	    SSL_CTX *ctx = SSL_CTX_new (SSLv23_server_method ());
	    SSL_CTX_set_options (ctx,
	            SSL_OP_SINGLE_DH_USE |
	            SSL_OP_SINGLE_ECDH_USE |
	            SSL_OP_NO_SSLv2);
	
	    /* Cheesily pick an elliptic curve to use with elliptic curve ciphersuites.
	     * We just hardcode a single curve which is reasonably decent.
	     * See http://www.mail-archive.com/openssl-dev@openssl.org/msg30957.html */
	    EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
	    if (! ecdh)
	        die_most_horribly_from_openssl_error ("EC_KEY_new_by_curve_name");
	    if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh))
	        die_most_horribly_from_openssl_error ("SSL_CTX_set_tmp_ecdh");
	
	    /* 选择服务器证书 和 服务器私钥. */
	    const char *certificate_chain = "server-certificate-chain.pem";
	    const char *private_key = "server-private-key.pem";
	    /* 设置服务器证书 和 服务器私钥 到 
	     OPENSSL ctx上下文句柄中 */
	    server_setup_certs (ctx, certificate_chain, private_key);
	
	    /* 
	        使我们创建好的evhttp句柄 支持 SSL加密
	        实际上,加密的动作和解密的动作都已经帮
	        我们自动完成,我们拿到的数据就已经解密之后的
	    */
	    evhttp_set_bevcb (http, bevcb, ctx);
	
	    /* 设置http回调函数 */
	    //默认回调
	    //evhttp_set_gencb (http, send_document_cb, NULL);
	    //专属uri路径回调
	    evhttp_set_cb(http, "/persistent", persistent_store_cb, NULL);
	    evhttp_set_cb(http, "/cache", cache_store_cb, NULL);
	
	    /* 设置监听IP和端口 */
	    handle = evhttp_bind_socket_with_handle (http, "0.0.0.0", serverPort);
	    if (! handle)
	    { 
	        fprintf (stderr, "couldn't bind to port %d. Exiting.\n",(int) serverPort);
	        return 1;
	    }
	
	    { 
	        /* 打印收到的客户端链接信息  */
	        sock_hop ss;
	        evutil_socket_t fd;
	        ev_socklen_t socklen = sizeof (ss);
	        char addrbuf[128];
	        void *inaddr;
	        const char *addr;
	        int got_port = -1;
	
	        fd = evhttp_bound_socket_get_fd (handle);
	        memset (&ss, 0, sizeof(ss));
	
	        if (getsockname (fd, &ss.sa, &socklen))
	        { 
	            perror ("getsockname() failed");
	            return 1;
	        }
	        if (ss.ss.ss_family == AF_INET)
	        { 
	            got_port = ntohs (ss.in.sin_port);
	            inaddr = &ss.in.sin_addr;
	        }
	        else if (ss.ss.ss_family == AF_INET6)
	        { 
	            got_port = ntohs (ss.i6.sin6_port);
	            inaddr = &ss.i6.sin6_addr;
	        }
	        else
	        { 
	            fprintf (stderr, "Weird address family %d\n", ss.ss.ss_family);
	            return 1;
	        }
	        addr = evutil_inet_ntop (ss.ss.ss_family, inaddr, addrbuf,
	                sizeof (addrbuf));
	        if (addr)
	            printf ("Listening on %s:%d\n", addr, got_port);
	        else
	        { 
	            fprintf (stderr, "evutil_inet_ntop failed\n");
	            return 1;
	        }
	    }
	
	    /* 开始阻塞监听 (永久执行) */
	    event_base_dispatch (base);
	
	
	    return 0;
	}
	
	int main (int argc, char **argv)
	{ 
	    /*OpenSSL 初始化 */
	    common_setup ();              
	
	    if (argc > 1) {
	        char *end_ptr;
	        long lp = strtol(argv[1], &end_ptr, 0);
	        if (*end_ptr) {
	            fprintf(stderr, "Invalid integer\n");
	            return -1;
	        }
	        if (lp <= 0) {
	            fprintf(stderr, "Port must be positive\n");
	            return -1;
	        }
	        if (lp >= USHRT_MAX) {
	            fprintf(stderr, "Port must fit 16-bit range\n");
	            return -1;
	        }
	
	        serverPort = (unsigned short)lp;
	    }
	    config_init();
	
	    /* now run http server (never returns) */
	    return serve_some_http ();
	}

cache.c

  • libevent搭建的服务器,回调函数的模板代码大部分都一致,主要关注于业务逻辑的处理

  • cachr.c中也没有进行业务逻辑的处理,拿到jason串后调用一个deal_cache进行处理

       response_data = deal_cache(request_data_buf);
    
  • 处理完的结果封装成json串还是会传到cache.c

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <limits.h>
      
      #include <sys/stat.h>
      #include <sys/socket.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <dirent.h>
      
      #include <openssl/ssl.h>
      #include <openssl/err.h>
      
      #include <event2/bufferevent.h>
      #include <event2/bufferevent_ssl.h>
      #include <event2/event.h>
      #include <event2/http.h>
      #include <event2/buffer.h>
      #include <event2/util.h>
      #include <event2/keyvalq_struct.h>
      
      #include <cJSON.h>
      
      #include "https-common.h"
      #include "busi_cb.h"
      #include "util.h"
      #include "make_log.h"
      void cache_store_cb (struct evhttp_request *req, void *arg)
      { 
          struct evbuffer *evb = NULL;
          const char *uri = evhttp_request_get_uri (req);
          struct evhttp_uri *decoded = NULL;
    
      /* 判断 req 是否是GET 请求 */
      if (evhttp_request_get_command (req) == EVHTTP_REQ_GET)
      {
          struct evbuffer *buf = evbuffer_new();
          if (buf == NULL) return;
          evbuffer_add_printf(buf, "Requested: %s\n", uri);
          evhttp_send_reply(req, HTTP_OK, "OK", buf);
          printf("get uri:%s\n", uri);
          LOG(LOG_MODULE_SERVER_DATA, LOG_PROC_CACHE, "get uri:%s\n", uri);
          return;
      }
    
      /* 这里只处理Post请求, Get请求,就直接return 200 OK  */
      if (evhttp_request_get_command (req) != EVHTTP_REQ_POST)
      { 
          evhttp_send_reply (req, 200, "OK", NULL);
          return;
      }
    
      LOG(LOG_MODULE_SERVER_DATA, LOG_PROC_CACHE, "Got a POST request for <%s>\n", uri);
    
      //判断此URI是否合法
      decoded = evhttp_uri_parse (uri);
      if (! decoded)
      { 
          LOG(LOG_MODULE_SERVER_DATA, LOG_PROC_CACHE, "It's not a good URI. Sending BADREQUEST\n");
          evhttp_send_error (req, HTTP_BADREQUEST, 0);
          return;
      }
    
      /* Decode the payload */
      struct evbuffer *buf = evhttp_request_get_input_buffer (req);
      evbuffer_add (buf, "", 1);    /* NUL-terminate the buffer */
      char *payload = (char *) evbuffer_pullup (buf, -1);
      int post_data_len = evbuffer_get_length(buf);
      char request_data_buf[4096] = {0};
      memcpy(request_data_buf, payload, post_data_len);
      LOG(LOG_MODULE_SERVER_DATA, LOG_PROC_CACHE, "[post_data][%d]=\n %s\n", post_data_len, payload);
    
    
      /*
         具体的:可以根据Post的参数执行相应操作,然后将结果输出
         ...
       */
      //=========================================
    
      char *response_data = NULL;
      response_data = deal_cache(request_data_buf);
      //response_data  need free at last
    
      //=========================================
      /* This holds the content we're sending. */
    
      //HTTP header
    
    
      evhttp_add_header(evhttp_request_get_output_headers(req), "Server", MYHTTPD_SIGNATURE);
      evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/plain; charset=UTF-8");
      evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
    
      evb = evbuffer_new ();
      evbuffer_add_printf(evb, "%s", response_data);
      //将封装好的evbuffer 发送给客户端
      evhttp_send_reply(req, HTTP_OK, "OK", evb);
    
      if (decoded)
          evhttp_uri_free (decoded);
      if (evb)
          evbuffer_free (evb);
    
      if (response_data != NULL) {
          LOG(LOG_MODULE_SERVER_DATA, LOG_PROC_CACHE, "[response]:\n");
          LOG(LOG_MODULE_SERVER_DATA, LOG_PROC_CACHE, "%s\n", response_data);
    
          free(response_data);
      }
    

    }

deal_cache.c

  • char * deal_cache(const char *request_data_buf):从传入的request_data_buf取出root和cmd,比较cmd执行不同的缓存操作

  • deal_cache_setLifecycle 处理生命周期:用封装的redis接口读取配置文件中的ip和port拿到redis句柄,取出json中的键和生命周期值联合句柄一起传入封装的redis接口,断开链接

      ret = rop_set_key_lifetime(conn, key->valuestring, lifecycle->valueint)
    
  • deal_cache_setString,处理setString指令,这是指设置一个Sting,(给司机,用户sessionid设置orderid),同样解析json对象拿到key,value,再拿到读取配置文件拿到句柄,调用封装的redis接口,同时给这个key设置一个默认的生命周期,断开句柄

  •   ret = rop_set_string(conn, key->valuestring, value->valuestring);
       rop_set_key_lifetime(conn, key->valuestring, lifecycle->valueint);
    
  • deal_cache_existKey,判断key是否存在

       if (rop_is_key_exist(conn, key->valuestring) == 1)
    
  • deal_cache_setHash:用来设置key:online-driver-[sessionid]的rvalues

      ret 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值