linux c++使用libevent编写http server + http client

本文详细介绍了如何在Linux环境下利用C++和libevent库来实现一个HTTP服务器以及对应的HTTP客户端。通过libevent的事件驱动模型,实现了高效地处理并发HTTP请求,同时展示了客户端发起HTTP请求并与服务器交互的过程。

http server:

/*
A trivial static http webserver using Libevent's evhttp.

This is not the best code in the world, and it does some fairly stupid stuff
that you would never want to do in a production webserver. Caveat hackor!

*/

/* Compatibility for possible missing IPv6 declarations */
//#include "../util-internal.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#ifndef S_ISDIR
#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
#endif
#else
#include <sys/stat.h>
#include <sys/socket.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#endif

#include <event2/event.h>
#include <event2/http.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>

#ifdef EVENT__HAVE_NETINET_IN_H
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#endif

#ifdef _WIN32
#ifndef stat
#define stat _stat
#endif
#ifndef fstat
#define fstat _fstat
#endif
#ifndef open
#define open _open
#endif
#ifndef close
#define close _close
#endif
#ifndef O_RDONLY
#define O_RDONLY _O_RDONLY
#endif
#endif

char uri_root[512];

static const struct table_entry {
	const char *extension;
	const char *content_type;
} content_type_table[] = {
	{ "txt", "text/plain" },
	{ "c", "text/plain" },
	{ "h", "text/plain" },
	{ "html", "text/html" },
	{ "htm", "text/htm" },
	{ "css", "text/css" },
	{ "gif", "image/gif" },
	{ "jpg", "image/jpeg" },
	{ "jpeg", "image/jpeg" },
	{ "png", "image/png" },
	{ "pdf", "application/pdf" },
	{ "ps", "application/postscript" },
	{ NULL, NULL },
};

/* Try to guess a good content-type for 'path' */
static const char *
guess_content_type(const char *path)
{
	const char *last_period, *extension;
	const struct table_entry *ent;
	last_period = strrchr(path, '.');
	if (!last_period || strchr(last_period, '/'))
		goto not_found; /* no exension */
	extension = last_period + 1;
	for (ent = &content_type_table[0]; ent->extension; ++ent) {
		if (!evutil_ascii_strcasecmp(ent->extension, extension))
			return ent->content_type;
	}

not_fo
Linux环境下使用C++编写一个支持1000线程并发的HTTP服务端,我们可以利用POSIX线程(`pthread`)来实现多线程处理。为了简化开发流程,我们也可以使用现代C++标准库中的线程支持(如 `<thread>` 和 `<mutex>`)。此外,我们还可以结合 `socket` 编程和 HTTP 协议的基础知识来构建一个简易的 HTTP 服务器。 以下是一个基于 C++ 的轻量级 HTTP 服务器示例,它能够为每个客户端连接创建一个独立线程进行处理,并支持并发访问: --- ### ✅ 功能说明: - 支持并发 1000 个线程 - 基于 TCP socket 实现 - 处理 GET 请求并返回简单响应 - 使用 C++11 标准及以上编译 --- ### ✅ 示例代码如下: ```cpp #include <iostream> #include <thread> #include <vector> #include <cstring> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> const int PORT = 8080; const int MAX_THREADS = 1000; void handle_client(int client_socket) { char buffer[3072]; ssize_t bytes_read = recv(client_socket, buffer, sizeof(buffer), 0); if (bytes_read > 0) { std::cout << "Received request:\n" << std::string(buffer, bytes_read) << std::endl; // 简单的 HTTP 响应 const char* response = "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n" "\r\n" "Hello from the server!"; send(client_socket, response, strlen(response), 0); } close(client_socket); // 关闭客户端连接 } int main() { int server_fd, new_socket; struct sockaddr_in address; int addrlen = sizeof(address); // 创建 socket 文件描述符 server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd == 0) { perror("Socket failed"); exit(EXIT_FAILURE); } // 设置地址和端口 address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // 绑定 socket 到指定端口 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); close(server_fd); exit(EXIT_FAILURE); } // 监听连接 if (listen(server_fd, SOMAXCONN) < 0) { perror("Listen failed"); close(server_fd); exit(EXIT_FAILURE); } std::cout << "Server is listening on port " << PORT << std::endl; std::vector<std::thread> thread_pool; thread_pool.reserve(MAX_THREADS); while (true) { // 接受客户端连接 new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen); if (new_socket < 0) { perror("Accept failed"); continue; } // 启动线程处理客户端请求 try { thread_pool.emplace_back(handle_client, new_socket); } catch (const std::system_error& e) { std::cerr << "Failed to create thread: " << e.what() << std::endl; close(new_socket); } } // 等待所有线程完成(理论上不会执行到这里) for (auto& t : thread_pool) { if (t.joinable()) { t.join(); } } close(server_fd); return 0; } ``` --- ### ✅ 编译与运行方式: ```bash g++ -std=c++11 -pthread http_server.cpp -o http_server ./http_server ``` 然后你可以用浏览器或 `curl` 测试: ```bash curl http://localhost:8080 ``` --- ### ✅ 关键点解释: 1. **线程池限制**:虽然我们设置了最大支持 1000 个线程,但在实际生产中,通常建议使用线程池(固定数量线程 + 队列任务分发)而不是为每个连接创建新线程。 2. **资源开销**:每个线程默认占用约 1MB 栈空间,因此 1000 线程将消耗大约 1GB 内存。 3. **性能优化建议**:可以改用异步 I/O 模型(如 `epoll`, `libevent`, `boost.asio`)来提高并发效率。 --- ### ✅ 如果你想使用 Qt 实现: Qt 提供了 `QTcpServer` 和 `QTcpSocket` 类来简化网络编程,你可以在主线程中监听连接,在子线程中处理请求。如果你需要,我可以提供 Qt 版本的实现。 --- ##
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值