使用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>*/

猜你喜欢

转载自blog.csdn.net/DANFBAORE/article/details/81027414