帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
服务器资讯 / 香港服务器租用 / 香港VPS租用 / 香港云服务器 / 美国服务器租用 / 台湾服务器租用 / 日本服务器租用 / 官方公告 / 帮助文档
libevent高并发网络编程 - 04_libevent实现http服务器
发布时间:2024-03-06 09:18:10   分类:帮助文档
libevent高并发网络编程 - 04_libevent实现http服务器 文章目录 1 evhttp简介2 相关的APIevhttp_new()evhttp_free()evhttp_bind_socket()evhttp_set_gencb()evhttp_set_cb()evhttp_request_get_uri()evhttp_request_get_command()evhttp_request_get_input_headers()evhttp_request_get_input_buffer()evhttp_request_get_output_headers()evhttp_add_header()evhttp_request_get_output_buffer()evhttp_send_reply() http服务器例子http服务器代码index.html文件运行效果 链接: C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂 1 evhttp简介 在libevent中,HTTP的实现主要是通过evhttp模块来完成的。evhttp提供了一个高层次的HTTP服务器接口,可以处理HTTP请求并发送HTTP响应。 在源码中,libevent的HTTP协议处理主要是通过evhttp模块来完成的。当客户端发起一个HTTP请求时,libevent将该请求解析为struct evhttp_request结构体表示,并调用用户设置的请求处理函数进行处理。 struct evhttp_request结构体定义了HTTP请求的各个字段,如请求行、请求头、请求正文等。例如,以下是struct evhttp_request结构体的部分定义: struct evhttp_request { int major; // 主版本号 int minor; // 次版本号 enum evhttp_cmd_type type; // 请求方法(GET、POST等) char *uri; // 请求URI struct evkeyvalq *input_headers;// 请求头 struct evbuffer *input_buffer; // 请求正文 }; enum evhttp_cmd_type { EVHTTP_REQ_GET = 1 << 0, EVHTTP_REQ_POST = 1 << 1, EVHTTP_REQ_HEAD = 1 << 2, EVHTTP_REQ_PUT = 1 << 3, EVHTTP_REQ_DELETE = 1 << 4, ..... }; 当接收到HTTP请求数据时,libevent将会使用一个状态机来逐步解析HTTP请求。在此过程中,它将从输入流中读取一些数据并按照HTTP协议格式解析这些数据,以获得请求的不同部分。具体来说,HTTP请求包括请求行、请求头和请求正文三个部分,每个部分都有其特定的格式。 将HTTP请求解析为struct evhttp_request结构体,libevent就会调用用户设置的请求处理函数来处理该请求。对于GET请求等不包含请求正文的请求,可以直接在请求处理函数中进行处理;对于POST请求等包含请求正文的请求,则需要从struct evhttp_request结构体中获取请求正文数据并进行处理。 总之,libevent使用状态机来逐步解析HTTP请求,并将请求解析为struct evhttp_request结构体表示。这种设计使得libevent能够高效地处理HTTP请求,同时也方便了开发者对HTTP协议进行扩展和定制。 2 相关的API evhttp_new() evhttp_new 用于创建和初始化一个 evhttp 结构体,以便用于 HTTP 服务器。 evhttp 结构体表示一个 HTTP 服务器,它可以在一个或多个套接字上监听传入的 HTTP 请求,并将这些请求分派给适当的请求处理程序。 struct evhttp * evhttp_new(struct event_base *base) base:即指向 `event_base` 结构体的指针,用于处理 HTTP 服务器的事件 evhttp_free() evhttp_free() 用于释放 evhttp 结构体及其相关资源。调用该函数后,将销毁与 evhttp 相关联的所有信息,包括绑定的套接字以及任何未完成的请求。 void evhttp_free(struct evhttp* http) evhttp_bind_socket() evhttp_bind_socket用于将HTTP服务器绑定到指定的IP地址和端口号。它接受一个指向evhttp结构体的指针,一个字符串表示IP地址,以及一个16位整数表示端口号。 int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port) 参数: http:指向要绑定的evhttp对象的指针。 address:要绑定的IP地址。可以是一个IPv4或IPv6地址,也可以是一个域名。如果为NULL,则默认绑定到所有可用地址。 port:要绑定的端口号。 evhttp_set_gencb() evhttp_set_gencb() 是 libevent 库中的一个函数,用于设置通用回调函数,该函数将在 HTTP 请求到达时被调用。 void evhttp_set_gencb(struct evhttp *http, void (*cb)(struct evhttp_request *, void *), void *cbarg) 第一个参数是指向 evhttp 结构体的指针,表示要设置回调函数的 HTTP 服务器; 第二个参数是指向回调函数的指针,该回调函数的原型为 void (*cb)(struct evhttp_request *, void *),其中第一个参数是指向当前 HTTP 请求的指针,第二个参数是传递给 evhttp_set_gencb() 函数的第三个参数; 第三个参数是传递给回调函数的上下文参数 cbarg,它可以是任何数据类型的指针; 当 HTTP 请求到达并且没有与之匹配的特定 URI 或处理程序时,将调用设置的通用回调函数。注意,如果已经为某个 URI 注册了特定的处理程序,则不会调用通用回调函数来处理该 URI 的请求。 evhttp_set_cb() evhttp_set_cb() 用于为 HTTP 服务器注册特定 URI 的请求处理程序回调函数。 evhttp_set_cb(struct evhttp *http, const char *uri, void (*cb)(struct evhttp_request *, void *), void *cbarg) 第一个参数是指向 evhttp 结构体的指针,表示要设置回调函数的 HTTP 服务器; 第二个参数是字符串类型的 URI,表示要注册回调函数的 URI; 第三个参数是指向回调函数的指针,该回调函数的原型为 void (*cb)(struct evhttp_request *, void *),其中第一个参数是指向当前 HTTP 请求的指针,第二个参数是传递给 evhttp_set_cb() 函数的第四个参数; 四个参数是传递给回调函数的上下文参数 cbarg,它可以是任何数据类型的指针。 当 HTTP 请求到达并且与所注册的 URI 匹配时,将调用设置的回调函数。注意,如果同时为相同的 URI 注册了多个回调函数,则只会调用最后一个注册的回调函数。 evhttp_request_get_uri() evhttp_request_get_uri() 用于获取 HTTP 请求的 URI(Uniform Resource Identifier)。 const char * evhttp_request_get_uri(const struct evhttp_request *req) { if (req->uri == NULL) event_debug(("%s: request %p has no uri\n", __func__, (void *)req)); return (req->uri); //返回struct evhttp_reques中的URI } 该函数只有一个参数,即指向 `evhttp_request` 结构体的指针,表示要获取 URI 的 HTTP 请求 函数返回一个字符串类型的指针,指向 HTTP 请求的 URI。URI 是客户端在请求服务器时发送的字符串,该字符串通常包含一个主机名、路径和查询字符串。例如,对于 “http://example.com/foo?bar=baz” 这样的请求,URI 将是 “/foo?bar=baz”。 需要注意的是,返回的指针指向的内存由 evhttp_request 结构体管理,因此不需要手动释放该指针指向的内存。 evhttp_request_get_command() evhttp_request_get_command() 用于获取 HTTP 请求的方法类型。 enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req) { return (req->type); //返回struct evhttp_reques中请求方法(GET、POST等) } 函数返回一个枚举类型 evhttp_cmd_type 值,表示 HTTP 请求使用的方法类型。枚举类型包括以下值: EVHTTP_REQ_GET: 使用 GET 方法。 EVHTTP_REQ_POST: 使用 POST 方法。 EVHTTP_REQ_HEAD: 使用 HEAD 方法。 EVHTTP_REQ_PUT: 使用 PUT 方法。 EVHTTP_REQ_DELETE: 使用 DELETE 方法。 EVHTTP_REQ_OPTIONS: 使用 OPTIONS 方法。 EVHTTP_REQ_TRACE: 使用 TRACE 方法。 EVHTTP_REQ_CONNECT: 使用 CONNECT 方法。 EVHTTP_REQ_PATCH: 使用 PATCH 方法。 evhttp_request_get_input_headers() evhttp_request_get_input_headers() 用于获取 HTTP 请求中的输入头部。输入头部是从客户端发送到服务器的数据块,其中包含一些元信息,例如请求的内容类型、长度或来源等。 struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req) { return (req->input_headers); // 返回struct evhttp_reques中请求头 } 函数返回一个指向 evkeyvalq 结构体的指针,该结构体代表了 HTTP 请求的输入头部。 该结构体是一个键值对列表,其中每个键都是头部的名称,每个值都是头部的值。 evhttp_request_get_input_buffer() evhttp_request_get_input_buffer() 用于获取 HTTP 请求的输入缓冲区。输入缓冲区是从客户端发送到服务器的数据块,其中包含了 HTTP 请求体以及可能的其他数据。 struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req) { return (req->input_buffer); // 返回struct evhttp_reques中请求正文 } 函数返回一个指向 evbuffer 结构体的指针,该结构体代表了 HTTP 请求的输入缓冲区。 evhttp_request_get_output_headers() evhttp_request_get_output_headers() 用于获取 HTTP 请求的输出头部。输出头部是从服务器发送到客户端的元信息块,其中包含了一些关于响应的信息,例如响应状态码、内容类型或其他自定义头部等。 struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req) { return (req->output_headers); } 函数返回一个指向 evkeyvalq 结构体的指针,该结构体代表了 HTTP 请求的输出头部。 该结构体是一个键值对列表,其中每个键都是头部的名称,每个值都是头部的值。 evhttp_add_header() evhttp_add_header()用于向 evkeyvalq 结构体表示的头部列表添加一个新的键值对。 int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value) 第一个参数是指向 evkeyvalq 结构体的指针,表示要添加头部的头部列表; 第二个参数是字符串类型的键名,表示要添加的头部的名称; 第三个参数是字符串类型的键值,表示要添加的头部的值。 需要注意的是,如果某个键已经存在于头部列表中,则会将现有键值对的值替换为新的值。如果要添加多个具有相同名称的头部,请使用逗号分隔它们的值。例如,可以使用"Accept-Encoding: gzip, deflate"来同时添加两个Accept-Encoding头部。 evhttp_request_get_output_buffer() evhttp_request_get_output_buffer() 用于获取 HTTP 请求的输出缓冲区。输出缓冲区是服务器发送到客户端的数据块,其中包含了 HTTP 响应体以及可能的其他数据。 struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req) { return (req->output_buffer); } 函数返回一个指向 evbuffer 结构体的指针,该结构体代表了 HTTP 请求的输出缓冲区。可以使用 evbuffer_add() 函数将内容添加到缓冲区中。 evhttp_send_reply() evhttp_send_reply() 用于向客户端发送 HTTP 响应。该函数使用指定的状态码、原因短语和响应正文来构造 HTTP 响应。 void evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *databuf) 第一个参数是指向 evhttp_request 结构体的指针,表示要发送响应的 HTTP 请求; 第二个参数是整数类型的状态码,表示响应的状态码; 第三个参数是字符串类型的原因短语,表示状态码的原因短语; 第四个参数是指向 evbuffer 结构体的指针,表示响应正文的内容。 需要注意的是,在调用 evhttp_send_reply() 函数之前,必须确保已经设置了响应状态码和必要的响应头部,并且已经将所有响应数据写入到输出缓冲区中。 http服务器例子 通过浏览器发送http请求,并解析url和http头部,并响应浏览器对文件和图片的请求。 http服务器代码 #include #include #include #include #include #include #ifndef _WIN32 #include #endif #include #include using namespace std; #define WEBROOT "." #define DEFAULTINDEX "index.html" void http_cb(struct evhttp_request *request, void *arg) { cout << "http_cb" << endl; //1 获取浏览器的请求信息 //uri const char *uri = evhttp_request_get_uri(request); cout << "uri:" << uri << endl; //请求类型 GET POST string cmdtype; switch (evhttp_request_get_command(request)) { case EVHTTP_REQ_GET: cmdtype = "GET"; break; case EVHTTP_REQ_POST: cmdtype = "POST"; break; } cout << "cmdtype:" << cmdtype << endl; // 消息报头 evkeyvalq *headers = evhttp_request_get_input_headers(request); cout << "====== headers ======" << endl; for (evkeyval *p = headers->tqh_first; p != NULL; p = p->next.tqe_next) { cout << p->key << ":" << p->value << endl; } // 请求正文 (GET为空,POST有表单信息 ) evbuffer *inbuf = evhttp_request_get_input_buffer(request); char buf[1024] = { 0 }; cout << "======= Input data ======" << endl; while (evbuffer_get_length(inbuf)) { int n = evbuffer_remove(inbuf, buf, sizeof(buf) - 1); if (n > 0) { buf[n] = '\0'; cout << buf << endl; } } //2 回复浏览器 //状态行 消息报头 响应正文 HTTP_NOTFOUND HTTP_INTERNAL string filepath = WEBROOT; filepath += uri; if (strcmp(uri, "/") == 0) { //默认加入首页文件 filepath += DEFAULTINDEX; } //消息报头 evkeyvalq *outhead = evhttp_request_get_output_headers(request); // 要支持 图片 js css 下载zip文件 // 获取文件的后缀 // ./index.html int pos = filepath.rfind('.'); string postfix = filepath.substr(pos + 1, filepath.size() - (pos + 1)); if (postfix == "jpg" || postfix == "gif" || postfix == "png") { string tmp = "image/" + postfix; evhttp_add_header(outhead, "Content-Type", tmp.c_str()); } else if (postfix == "zip") { evhttp_add_header(outhead, "Content-Type", "application/zip"); } else if (postfix == "html") { evhttp_add_header(outhead, "Content-Type", "text/html;charset=UTF8"); //evhttp_add_header(outhead, "Content-Type", "text/html"); } else if (postfix == "css") { evhttp_add_header(outhead, "Content-Type", "text/css"); } //读取html文件返回正文 FILE *fp = fopen(filepath.c_str(), "rb"); if (!fp) { evhttp_send_reply(request, HTTP_NOTFOUND, "", 0); return; } evbuffer *outbuf = evhttp_request_get_output_buffer(request); for (;;) { int len = fread(buf, 1, sizeof(buf), fp); if (len <= 0)break; evbuffer_add(outbuf, buf, len); } fclose(fp); evhttp_send_reply(request, HTTP_OK, "", outbuf); } int main(int argc,char *argv[]) { #ifdef _WIN32 //初始化socket库 WSADATA wsa; WSAStartup(MAKEWORD(2,2),&wsa); #else //忽略管道信号,发送数据给已关闭的socket if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return 1; #endif std::cout << "test server!\n"; //创建libevent的上下文 event_base * base = event_base_new(); if (base) { cout << "event_base_new success!" << endl; } // http 服务器 //1 创建evhttp上下文 evhttp *evh = evhttp_new(base); //2 绑定端口和IP if (evhttp_bind_socket(evh, "0.0.0.0", 8080) != 0) { cout << "evhttp_bind_socket failed!" << endl; } //3 设定回调函数 evhttp_set_gencb(evh, http_cb, 0); //事件分发处理 if(base) event_base_dispatch(base); if(base) event_base_free(base); if(evh) evhttp_free(evh); return 0; } index.html文件 test http server

test http server

1234567890 测试中文
运行效果
香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价