1. 程式人生 > >使用LIBEVENT構建HTTP服務

使用LIBEVENT構建HTTP服務

//開啟服務
void startHttpServer(int port)
{
WSADATA wsaData;
WSAStartup(0x0202, &wsaData);

//建立監聽SOCKET  啟動http服務
int fd = socket(AF_INET, SOCK_STREAM, 0);
int one = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
perror("");
log("bind error!\n");
return ;
}

if (listen(fd, 0x7fffffff) == -1) {
log("listen error!\n");
return ;
}
setnonblocking(fd);

int len = sizeof(addr);
if (getsockname(fd, (struct sockaddr *)&addr, &len) != 0) {
log("getsockname error!\n");
return ;
}

//處理http請求  可以設定多個請求防止一個阻塞。
int i;
for (i = 0; i < THR_NUM - 1; ++i) {
struct event_base *base = event_init();
struct evhttp *httpd = evhttp_new(base);
evhttp_accept_socket(httpd, fd);//將SOCKET與HTTP服務繫結。
//evhttp_set_timeout(httpd, timeout);
evhttp_set_gencb(httpd, genericHandle, NULL);//使用者請求的回撥介面。
                //開啟執行緒 處理HTTP請求
HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, dispatch, base, 0, NULL); 
if( hThread1 != NULL )   
{      
CloseHandle(hThread1);   

}

struct event_base *base = event_init();
struct evhttp *httpd = evhttp_new(base);
evhttp_accept_socket(httpd, fd);
//evhttp_set_timeout(httpd, timeout);
evhttp_set_gencb(httpd, genericHandle, NULL);
event_base_dispatch(base);

}

//設定網路非阻塞。

void setnonblocking(SOCKET sock)
{
u_long ulArg = 1;
if (::ioctlsocket(sock, FIONBIO, &ulArg) == SOCKET_ERROR) {
log("ioctlsocket error\n");
}
}

//執行緒中只調用等待即可。
unsigned int STDCALL dispatch(void* arg)
{
event_base_dispatch((struct event_base*)arg);
return NULL;

}

//處理使用者發出的請求

void 
OpenClient(struct evhttp_request* req, struct evkeyvalq* query_headers, int* response_code, struct evbuffer *response_buf)
{
const char* type = evhttp_find_header(query_headers, "type");
if (type == NULL) {
*response_code = HTTP_INTERNAL;
log("type == NULL");
return;
}

char* response_data ="{\"ret\":0}";//需要返回的資訊,可以是JSON等約定型別的串。
evbuffer_add(response_buf, response_data, strlen(response_data) + 1);
free(response_data);

}

//處理接收的命令

void genericHandle(struct evhttp_request* req, void *arg)
{
const struct evhttp_uri* uri = evhttp_request_get_evhttp_uri(req);
const char* path = evhttp_uri_get_path(uri);
const char* query_str = evhttp_uri_get_query(uri);
struct evkeyvalq headers;
if (evhttp_parse_query_str(query_str, &headers) == -1) {
log("evhttp_parse_query_str error!\n");
return;
}

int response_code = HTTP_OK;
struct evbuffer *buf = evbuffer_new();
size_t post_size = EVBUFFER_LENGTH(req->input_buffer);
if (post_size > 0)//用這種方式處理POST中BODY的資料。
{
char* pcBuf = new char[post_size + 1];
memset(pcBuf,0,post_size+1);
memcpy (pcBuf, EVBUFFER_DATA(req->input_buffer), post_size);

if (strcmp(path, "/SendMessageToProcess") == 0) {//這兒解析命令
//--
} else if (strcmp(path, "/StartProcessWithParam") == 0) {
//--

else
{
return;//命令錯誤
}

char* response_data = "";
evbuffer_add(buf, response_data, strlen(response_data) + 1);
free(response_data);

// char buf[1024] = {0};
// evbuffer_remove(req->input_buffer, &buf, sizeof(buf) - 1);
// event_base_loopbreak((struct event_base*)arg);
//這種資料是約定好的,可能是JSON,或純資料,可以是大檔案。
delete []pcBuf;
}
else
{
//解析HTTP請求的命令  GET?
string strTmp = path;

                //分割傳入的命令。
vector<string> vecInput = split(path,"/");
if (vecInput.size() > 0)
{
if (vecInput[0] == "StartProcessWithParam")//解析命令
{
}
}
}

// No 'Access-Control-Allow-Origin' header is present on the requested resource//解決跨域呼叫返回的報錯問題 
evhttp_add_header(evhttp_request_get_output_headers(req), "Access-Control-Allow-Origin","*"); 

evhttp_send_reply(req, response_code, "ok", buf);
evbuffer_free(buf);

}

//字串分割函式
vector< string> split( string str, string pattern)
{
vector<string> ret;
if(pattern.empty()) return ret;
size_t start=0,index=str.find_first_of(pattern,0);
while(index!=str.npos)
{
if(start!=index)
ret.push_back(str.substr(start,index-start));
start=index+1;
index=str.find_first_of(pattern,start);
}
if(!str.substr(start).empty())
ret.push_back(str.substr(start));
return ret;

}

//使用方法:將LIBEVENT引入,在UI層開啟執行緒呼叫  startHttpServer傳入埠號即可。

/*

_beginthread(ThreadHttpServer,0,this);

void ThreadHttpServer( void *dummy )
{
startHttpServer(埠號);
}

*/


//網頁POST格式:

/*
注意客戶端須有:xhrFields: { //允許跨域訪問是新增cookie
withCredentials: false
}, 或者不加此項,不能為TRUE。
如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Access-Control-Allow-Origin" content="*" />
<title>Insert title here</title>
<script type="text/javascript" src="jquery-1.8.3.js"></script>
<script type="text/javascript">
function start() {
jQuery.support.cors = true; 
$.ajax({
url : 'http://127.0.0.1:8003/SendMessageToProcess',
type : "post",
data : {  //這樣傳輸後資料格式為 type=sdk&param=s  
type : "1",
param : "5"
},
//以下為JSON格式資料。
// data : JSON.stringify({
// type : "1",
// param : " gf"
// }),
success : function(data) {
console.log(data)
}
});
}
</script>
</head>
<body>
<button onclick="start()">測試</button>
</body>
</html>*/