简单的请求访问:
浏览器请求相应的url,得到text,html, jpg, zip文件下载,提交表单等操作
main.cpp
#include <iostream>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/keyvalq_struct.h>
#include <event2/buffer.h>
#include <string.h>
#include <string>
#include <event2/listener.h>
#define SPORT 5001
#ifndef _WIN32
#include <signal.h>
#endif
using namespace std;
#define WEBROOT "."
#define DEFAULTINDEX "index.html"
void http_cb(struct evhttp_request* request, void* arg)
{
cout << "http_cb" << endl;
//1. 获取浏览器的请求信息
//uri 网路资源地址 若url="http://127.0.0.1:8080/index.html"(则uri="/index.html")
const char* uri = evhttp_request_get_uri(request);
cout << "uri:" << uri << endl;
//请求类型
string cmdtype;
switch (evhttp_request_get_command(request))
{
case EVHTTP_REQ_GET:
cmdtype = "GET";
break;
case EVHTTP_REQ_POST:
cmdtype = "POST";
break;
default:
break;
}
cout << "cmdtype; " << cmdtype << endl;
//消息报头
evkeyvalq* headers = evhttp_request_get_input_headers(request);
cout << "======headers: =======\n";
for (evkeyval* p = headers->tqh_first; p != NULL; p = p->next.tqe_next) {
cout << p->key << ":" << p->value << endl;
}
//请求正文(GET=NULL, POST有表单信息)
evbuffer* inbuf = evhttp_request_get_input_buffer(request);
char buf[1024] = { 0 };
cout << "=============inbuf==============" << 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_OK=200 HTTP_NOTFOUND=404 HTTP_INTERNAL=500
// 分析出请求的文件uri
// 设置根目录 WEBROOT
// windows C/C++预处理器 添加 _CRT_SECURE_NO_WARNINGS
string filepath = WEBROOT;
filepath += uri;
if (strcmp(uri, "/") == 0)
{
//默认加入首页文件
filepath += DEFAULTINDEX;
}
//消息报头
evkeyvalq* outhead = evhttp_request_get_output_headers(request);
// 支持图片,js,css,下载普通zip文件
// 获取文件的后缀名
// ./root/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");
}
else if (postfix == "js")
{
evhttp_add_header(outhead, "Content-Type", "text/js");
}
//读取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, "200 OK", 6);
evbuffer_add(outbuf, buf, len);
}
fclose(fp);
evhttp_send_reply(request, HTTP_OK, "", outbuf);
}
int main(int argc, char** argv) {
#if _WIN32
//windowns 初始化socket库
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
#else
//linux 忽略管道信号,发送数据给已关闭的socket
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
event_base* base = event_base_new();
if (base) {
std::cout << "event_base_new init successfuly!" << std::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);
}
#ifdef _WIN32
WSACleanup();
#endif // _WIN32
return 0;
}
index.html
<HTML>
<HEAD>
<meta charset="utf-8" />
<TITLE>test http server</TITLE>
</HEAD>
<BODY>
<h1>test http server h1</h1>
<h2>this is a test!</h2>
<h2>这是http服务!</h2>
<img src="test.jpg" />
<form method="post">
<input type="text" name="username"/>
<input type="password" name="password"/>
<input type="submit" name="submit" />
</form>
</BODY>
</HTML>
浏览器展示:
访问:http://127.0.0.1:8080/
服务端终端: