Linux C++ 基于libevent实操简单的http协议

17 篇文章 0 订阅
  • 已解决传输大文件问题
  • 新增post数据接收(处理自定义)及返回

server.cpp

#include <event2/event.h>
#include <event2/listener.h>
#include <event2/http.h>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
#include <string.h>
#include <string>
#ifndef _WIN32
	#include<signal.h> //linux适配
#endif
#include <iostream>
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 << "************请求头数据************" << endl;
	//请求正文
	for (evkeyval *p = headers->tqh_first; p != NULL; p = p->next.tqe_next){
		cout << p->key << ":" << p->value << endl;
	}
	cout<<"**********************************"<<endl;

	//请求正文(GET为空,POST有表单信息)
	evbuffer *inbuf = evhttp_request_get_input_buffer(request);
	char buf[1024] = { 0 };
	cout<<"========获取POST请求数据(GET请求没有数据)========"<<endl;
	while (evbuffer_get_length(inbuf)){
		int n = evbuffer_remove(inbuf, buf, sizeof(buf) - 1);
		if (n > 0){
			buf[n] = '\0';
			cout << buf << endl;
		}
	}
	cout<<"=================================="<<endl<<endl<<endl;


	//2. 回复浏览器
	//状态行 消息头  响应正文 HTTP_NOTFOUND HTTP_INTERNAL

	//分析出请求的文件 uri
	//设置根目录 WEBROOT
	string filepath = WEBROOT;
	filepath += uri;
	if (strcmp(uri, "/") == 0){
		//默认加上首页文件
		filepath += DEFAULTINDEX;
	}
	//消息报头
	evkeyvalq *outhead = evhttp_request_get_output_headers(request);//outhead为响应头
	//要支持图片 CSS  js  下载zip文件
	//获取文件的后缀名
	int pos = filepath.rfind('.');
	string file_type = filepath.substr(pos + 1, filepath.length() - (pos + 1));
	if (file_type == "jpg" || file_type == "gif" || file_type == "png"){
		string temp = "image/" + file_type; //响应图片类型
		evhttp_add_header(outhead, "Content-Type", temp.c_str());
	}else if (file_type == "zip"){
		evhttp_add_header(outhead, "Content-Type", "application/zip");
	}else if (file_type == "html"){
		evhttp_add_header(outhead, "Content-Type", "text/html;charset=UTF-8");
	}else if (file_type == "css"){
		evhttp_add_header(outhead, "Content-Type", "text/css");
	}else if(file_type == "zz"){//为了知道是POST请求,我将后缀识别为.zz类型
		//这里表示是POST请求
		evhttp_add_header(outhead, "Content-Type", "application/html");
		evbuffer *outbuf = evhttp_request_get_output_buffer(request); //返回的body
		string json = "{\"res\":100,\"text\":\"OK\",\"data\":null}"; //模拟json数据
		evbuffer_add(outbuf, json.c_str(), json.length());
		evhttp_send_reply(request, HTTP_OK, "", outbuf);
		return;
	}


	//读取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); //返回的body
	while (true){
		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(){
#ifdef _WIN32
	//初始化socket库
	WSADATA wsa;
	WSAStartup(MAKEWORD(2,2), &wsa);
#else
	//忽略管道信号, 发送数据给已关闭的socket
	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)return 1;
#endif
    std::cout << "测试的http服务器\n"; 
	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", 8000) != 0){//全部IP可访问
		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

}

makefile

server:server.cpp
	g++ $^ -o $@ -levent
clean:
	rm -rf server
	rm -rf *o

index.html

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Hello World</title>
</head>
<body>
	<h1>Hello World</h1>
    <img src="big_pic.jpg" width="20%" />
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script type="text/javascript">
    	$(function(){
    		$.ajax({
	    		url:'/post_data.zz',
	    		type:'post',
	    		data:{
	    			name:"this is name",
	    			text:"Hello World"
	    		},
	    		dataType:"json",
	    		success:function(res){
	    			console.log(res)
	    		},error:function(res){
	    			console.log(res)
	    		},complete:function(){
	    			console.log("请求结束!")
	    		}
	    	});
    	});
    </script>
</body>


</html>

在这里插入图片描述
在这里插入图片描述

效果:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
虽然看上去已经实现功能,但是经不起真实业务场景的考验都只不过是玩具(Linux 如何对http服务器进行压力测试

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值