1. 程式人生 > >用libevent開發一個http服務端,附帶一個curl http客戶端

用libevent開發一個http服務端,附帶一個curl http客戶端

對http互動較為陌生,所以最近寫了兩個小demo,一個http server 和一個http client,對於http server,很多人推薦使用libevent。

http server:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

//libevent http server header files
#include <event2/http.h>
#include <sys/queue.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/http_compat.h>
#include <event2/http_struct.h>
#include <event2/buffer_compat.h>

void generic_cb(struct evhttp_request* req, void* arg)
{
    char* s = "This is the generic buf";
    const struct evhttp_uri* evhttp_uri = evhttp_request_get_evhttp_uri(req);
    char url[8192];
    evhttp_uri_join(const_cast<struct evhttp_uri*>(evhttp_uri), url, 8192);
    printf("accept req url:%s\n", url);
	
	
	/*
	//解析URI的引數(即GET方法的引數)
	struct evkeyvalq params;
	evhttp_parse_query(decoded_uri, ¶ms);
	printf("q=%s\n", evhttp_find_header(¶ms, "q"));
	printf("s=%s\n", evhttp_find_header(¶ms, "s"));
	free(decoded_uri);
	*/
	
	char *post_data = (char *) EVBUFFER_DATA(req->input_buffer);
	printf("post info\n :%s\n", post_data);
	
	//HTTP header
	evhttp_add_header(req->output_headers, "Server", "myhttpd v 0.0.1");
	evhttp_add_header(req->output_headers, "Content-Type", "text/plain; charset=UTF-8");
	evhttp_add_header(req->output_headers, "Connection", "close");
	
    struct evbuffer* evbuf = evbuffer_new();
    if (!evbuf)
    {
        printf("create evbuffer failed!\n");
        return ;
    }
    evbuffer_add_printf(evbuf, "Server response. Your req url is %s", url);
    evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
    evbuffer_free(evbuf);

}

void test_cb(struct evhttp_request* req, void* arg)
{
    char* s = "This is the test buf";
    const struct evhttp_uri* evhttp_uri = evhttp_request_get_evhttp_uri(req);
    char url[8192];
    evhttp_uri_join(const_cast<struct evhttp_uri*>(evhttp_uri), url, 8192);

    printf("accept req url:%s\n", url);

    struct evbuffer* evbuf = evbuffer_new();
    if (!evbuf)
    {
        printf("create evbuffer failed!\n");
        return ;
    }

    evbuffer_add_printf(evbuf, "Server response. Your req url is %s", url);
    evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
    evbuffer_free(evbuf);

}

int main()
{
    short http_port = 8081;
    char* http_addr = "0.0.0.0";

    struct event_base* base = event_base_new();
    struct evhttp* http_server = evhttp_new(base);
    if(NULL == http_server)
    {
        return -1;
    }

    int ret = evhttp_bind_socket(http_server, http_addr, http_port);
    if(ret != 0)
    {
        return -1;
    }

    evhttp_set_cb(http_server, "/test", test_cb, (void*)"arg");
    evhttp_set_gencb(http_server, generic_cb, NULL);
    printf("http server start OK!\n");
    event_base_dispatch(base);
    evhttp_free(http_server);

    return 0;
}

為了驗證,寫了一個客戶端驗證一下,curl http client:

#include<sys/types.h>  
#include<sys/socket.h>  
#include<netinet/in.h>  
#include<arpa/inet.h>  
#include<errno.h>  
#include<unistd.h>  
  
#include<stdio.h>  
#include<string.h>  
#include<stdlib.h>  
#include <ctime>
#include <string.h>

#include "TdaInteraction.h"
#include "jsoncpp/value.h"
#include "jsoncpp/reader.h"
  
size_t GetOptCallBack(void *pBuf, size_t nSize, size_t nCount, void *stream)
{
    if (stream  == NULL ||
        pBuf    == NULL)
    {
        return 0;
    }
	
    ((std::string*)stream)->append((char*)pBuf, 0, nSize* nCount);

    return nSize * nCount;
}

bool PostRequest(const std::string& strJsonIn,std::string strDeviceId,std::string strHost,std::string& strJsonOut)
{
	long  nStatCode  = 0;
	char  szUrl[102];
	CURL* pCurl = curl_easy_init();
	if (NULL == pCurl)
    {
        printf("Request Error:Init Curl Failed\n");
        return false;
    }

	curl_slist *http_headers = NULL;
	PostHeader(&http_headers,strHost,strJsonIn.size());
	curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, http_headers);

	// 設定下載地址
	memset(szUrl,0x0,sizeof(szUrl));
	sprintf(szUrl,"http://%s:8081/tda/v1/intconfigs",strHost.data());
    curl_easy_setopt(pCurl, CURLOPT_URL, szUrl); 
	curl_easy_setopt(pCurl, CURLOPT_POST, 1);//設定為非0表示本次操作為POST
	// 設定要POST的JSON資料
    curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, strJsonIn.c_str());
    curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE, strJsonIn.size());//設定上傳json串長度,這個設定可以忽略

	// 回撥資料
    std::string strData;
    curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, GetOptCallBack);
    curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &strData);

	// 執行
    int nRet = curl_easy_perform(pCurl);
	if (nRet != CURLE_OK)
    {
        printf("curl_easy_perform error %d, url = %s\n", nRet,szUrl);
        //釋放curl資源
        curl_easy_cleanup(pCurl);

        return false;
    }

     nRet = curl_easy_getinfo(pCurl, CURLINFO_RESPONSE_CODE , &nStatCode); 
     if (nRet != CURLE_OK || nStatCode != 200)
     {
         printf("curl_easy_getinfo error %x, status code %d, url = %s\n, %s\n", nRet, nStatCode,szUrl,strData.data());
         //釋放curl資源
         curl_slist_free_all(http_headers);
         curl_easy_cleanup(pCurl);
         return false;
     }
	 
	curl_slist_free_all(http_headers);
    curl_easy_cleanup(pCurl);

	strJsonOut = std::move(strData);
	return true;
}


int PostHeader(curl_slist **http_headers,std::string strHost,int nLen)
{
	std::string strDate;
	std::string strToken;
	std::string strLen = std::to_string(nLen);
	GetDateTime(strDate);
	*http_headers = curl_slist_append(*http_headers, std::string("Host: ").append(strHost).c_str());
        *http_headers = curl_slist_append(*http_headers, std::string("Date: ").append(strDate).c_str());
	*http_headers = curl_slist_append(*http_headers, "Content-Type: application/json; charset=utf-8");
        //*http_headers = curl_slist_append(*http_headers, std::string("Token: ").append(strToken).c_str());
	*http_headers = curl_slist_append(*http_headers, std::string("Content-Length: ").append(strLen).c_str());
        *http_headers = curl_slist_append(*http_headers, "Connection: Keep-Alive/close");
	return 0;
}

void GetDateTime(std::string& date_time)
{
	time_t now = (time_t)0;
	struct tm* gmt = NULL;

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

	time(&now);
	gmt = gmtime(&now);

	char time_val[65]; 
	memset(time_val, '\0', 65);

	strftime(time_val, 64, "%a, %d %b %Y %H:%M:%S GMT", gmt);
	date_time = time_val;
	return;
}

int main(int argc, char** argv)  
{  
	CTdaInteraction cTda;
	std::string strHost = "10.12.5.17";
	std::string strJsonOut;
	Json::Value jvData;
	jvData["method"] = "GetList";
	jvData["name"] = "zsk";
	jvData["pwd"] = "423200";
	std::string strJson = jvData.toStyledString();
        bool bRet = PostRequest(strJson,"",strHost,strJsonOut);
	if(!bRet)
	{
		printf("Get Task Status Error. bRet = %d\n",bRet);
	}
	else
	{
		printf("Get Task %s\n",strJsonOut.data());
	}
	
        return 0;  
}