libevent evhttp多线程

Posted byxdaz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libevent evhttp多线程相关的知识,希望对你有一定的参考价值。

一、多线程流程:
1、创建socket,绑定port
2、多线程,每个线程申请event_base和evhttp,通过evhttp_accept_socket绑定。

int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)使http server可以接受来自指定的socket的连接,可重复调用来绑定到不同的socket。
(1)http为待绑定的http server指针
(2)fd为待绑定的socket(该socket应已准备好接受连接)    0表示成功,-1表示失败    
跟此函数类似的一个函数为evhttp_accept_socket_with_handle,其声明是struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd); 与evhttp_accept_socket唯一不同的地方是返回值不同,它返回了一个socket句柄

二、http server多线程代码

#include <event.h>
#include <evhttp.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <vector>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/http.h>
#include <event2/buffer.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>
#include <event2/thread.h>
 
int httpserver_bindsocket(int port, int backlog);
int httpserver_start(int port, int nthreads, int backlog);
void* httpserver_Dispatch(void *arg);
void httpserver_GenericHandler(struct evhttp_request *req, void *arg);
void httpserver_ProcessRequest(struct evhttp_request *req);
 
evutil_socket_t httpserver_bindsocket(int port, int backlog) 
  int rt;
  evutil_socket_t sock
  sock= socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	
		perror("could not create socket");
		return -1;
	
 
	rt = evutil_make_listen_socket_reuseable(sock);
	if (rt < 0)
	
		perror("cannot make socket reuseable");
		return -1;
	
 
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);
 
rt = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
	if (rt < 0)
	
		perror("cannot bind socket");
		return -1;
	

	rt = listen(sock, 1024);
	if (rt < 0)
	
		perror("cannot listen");
		return -1;
	
	rt = evutil_make_socket_nonblocking(sock);
	if (rt < 0)
	
		perror("cannot make socket non blocking");
		return -1;
	
  
  return sock;

 
int httpserver_start(int port, int nthreads, int backlog) 
  evthread_use_pthreads(); //ok if called from other places
  std::vector<base *> vecBase;
  int r, i;
  evutil_socket_t nfd = httpserver_bindsocket(port, backlog);
  if (nfd < 0) return -1;
  pthread_t ths[nthreads];
  for (i = 0; i < nthreads; i++) 
    struct event_base *base = event_init();
    if (base == NULL) return -1;
    vecBase.push_back(base);
    struct evhttp *httpd = evhttp_new(base);
    if (httpd == NULL) return -1;
    r = evhttp_accept_socket(httpd, nfd);
    if (r != 0) return -1;
    evhttp_set_gencb(httpd, httpserver_GenericHandler, NULL);
    r = pthread_create(&ths[i], NULL, httpserver_Dispatch, base);
    if (r != 0) return -1;
  
  for (i = 0; i < nthreads; i++) 
    pthread_join(ths[i], NULL);
  

  //exit
  for (i = 0; i < nthreads; i++) 
  event_base_loopbreak(vecBase[i]);

  evutil_closesocket(nfd);

 
void* httpserver_Dispatch(void *arg) 
  event_base_dispatch((struct event_base*)arg);
  return NULL;

 
void httpserver_GenericHandler(struct evhttp_request *req, void *arg) 
      httpserver_ProcessRequest(req);

 
void httpserver_ProcessRequest(struct evhttp_request *req) 
    struct evbuffer *buf = evbuffer_new();
    if (buf == NULL) return;
    
    //here comes the magic

 
int main(void) 
    httpserver_start(8081, 10, 10240);
	

三、http client代码

#include <event2/event_struct.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/http.h>
#include "evhttp.h"
 
int init_win_socket()

	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	
		return -1;
	
	return 0;

 
//http请求回调函数,用于处理服务器端的返回消息
void http_request_done(struct evhttp_request *req, void *arg)

	printf("send request ok...\\n");
	size_t len = evbuffer_get_length(req->input_buffer);
	unsigned char * str = evbuffer_pullup(req->input_buffer, len);
	char buf[256] =  0 ;
	memcpy(buf, str, len);
	if (str == NULL)
	
		printf("len = %d, str == NULL\\n", len);
	
	else
	
		printf("len = %d, str = %s\\n", len, buf);
	
 
	event_base_loopbreak((struct event_base*)arg);

 
int main()

	struct event_base* base;
	struct evhttp_connection* conn;
	struct evhttp_request* req;
#ifdef WIN32
	init_win_socket();
#endif
 
	base = event_base_new();
	conn = evhttp_connection_new("127.0.0.1", 8081);
	evhttp_connection_set_base(conn, base);
 
 
	req = evhttp_request_new(http_request_done, base);  //创建http请求对象
	evhttp_add_header(req->output_headers, "Host", "localhost");  //填充http请求头内容
	evhttp_make_request(conn, req, EVHTTP_REQ_GET, "/test");  //发送http请求
	evhttp_connection_set_timeout(req->evcon, 600);  //设置超时时间,超过这个时间还没收到服务端消息,则自动回调本地回调函数http_request_done
 
	event_base_dispatch(base); 
	evhttp_connection_free(conn);
	event_base_free(base);
	printf("run over...\\n");
 
	system("pause");
	return 0;

以上是关于libevent evhttp多线程的主要内容,如果未能解决你的问题,请参考以下文章

libevent evhttp多线程

libevent evhttp多线程

libevent(十三)evhttp事件处理流程

libevent evhttp使用

Libevent::evhttp服务器下载

使用基于 libevent 的 evhttp 的服务器打开的文件过多