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;
}

猜你喜欢

转载自blog.csdn.net/byxdaz/article/details/126867947