用libevent開發一個http服務端,附帶一個curl http客戶端
阿新 • • 發佈:2019-01-04
對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; }