解析muduo源码之 HttpServer.h & HttpServer.cc

目录

[一、 HttpServer.h](#一、 HttpServer.h)

[1. 一句话定位](#1. 一句话定位)

[2. 类结构](#2. 类结构)

[3. 核心:用户回调](#3. 核心:用户回调)

[4. HttpServer 工作流程](#4. HttpServer 工作流程)

[5. HttpServer 内部组件关系](#5. HttpServer 内部组件关系)

[6. 为什么 HttpServer 如此简单](#6. 为什么 HttpServer 如此简单)

[二、 HttpServer.cc](#二、 HttpServer.cc)

[1. 一句话总结](#1. 一句话总结)

[2. 默认回调](#2. 默认回调)

[3. 构造函数 HttpServer::HttpServer ()](#3. 构造函数 HttpServer::HttpServer ())

[4. 连接建立:onConnection ()](#4. 连接建立:onConnection ())

[5. 消息到达:onMessage ()](#5. 消息到达:onMessage ())

[6. 请求处理:onRequest ()](#6. 请求处理:onRequest ())

[7. HttpServer 工作全流程图](#7. HttpServer 工作全流程图)

[8. HttpServer 最核心的作用](#8. HttpServer 最核心的作用)


一、 HttpServer.h

先贴出完整代码,再逐部分解释:

cpp 复制代码
// Copyright 2010, Shuo Chen. 保留所有权利。
// http://code.google.com/p/muduo/
//
// 本源代码的使用受 BSD 许可证约束
// 可在 License 文件中找到许可证条款。

// 作者:陈硕 (chenshuo at chenshuo dot com)
//
// 这是公共头文件,只能包含公共头文件。

#ifndef MUDUO_NET_HTTP_HTTPSERVER_H
#define MUDUO_NET_HTTP_HTTPSERVER_H

#include "muduo/net/TcpServer.h"

namespace muduo
{
namespace net
{

class HttpRequest;
class HttpResponse;

///
/// 简单可嵌入式 HTTP 服务器
/// 主要用于程序状态上报
/// 并非完整兼容 HTTP/1.1,但能与浏览器、HTTP 客户端正常通信
/// 同步处理模型,类似 Java Servlet
///
class HttpServer : noncopyable
{
 public:
  /// HTTP 请求回调函数类型
  /// 参数:解析好的请求、用于填写回复的响应对象
  typedef std::function<void (const HttpRequest&, HttpResponse*)> HttpCallback;

  /// 构造函数
  /// @param loop 主事件循环
  /// @param listenAddr 监听地址
  /// @param name 服务器名称
  /// @param option 端口复用选项
  HttpServer(EventLoop* loop,
             const InetAddress& listenAddr,
             const string& name,
             TcpServer::Option option = TcpServer::kNoReusePort);

  /// 获取事件循环
  EventLoop* getLoop() const { return server_.getLoop(); }

  /// 设置 HTTP 请求处理回调
  /// 非线程安全,必须在 start() 之前注册
  void setHttpCallback(const HttpCallback& cb)
  {
    httpCallback_ = cb;
  }

  /// 设置 IO 线程池数量
  void setThreadNum(int numThreads)
  {
    server_.setThreadNum(numThreads);
  }

  /// 启动服务器
  void start();

 private:
  /// TCP 连接建立/断开回调
  void onConnection(const TcpConnectionPtr& conn);

  /// TCP 消息到达回调(接收数据、解析 HTTP)
  void onMessage(const TcpConnectionPtr& conn,
                 Buffer* buf,
                 Timestamp receiveTime);

  /// HTTP 请求解析完成后回调(处理业务)
  void onRequest(const TcpConnectionPtr&, const HttpRequest&);

  TcpServer server_;       // 底层 TCP 服务器
  HttpCallback httpCallback_; // 用户设置的 HTTP 业务回调
};

}  // namespace net
}  // namespace muduo

#endif  // MUDUO_NET_HTTP_HTTPSERVER_H

1. 一句话定位

HttpServer = 基于 TcpServer 封装的 HTTP 专用服务器

  • 内部持有一个 TcpServer
  • 帮你自动处理 HTTP 解析
  • 帮你自动处理请求 / 响应
  • 给用户提供极简 HTTP 回调接口
  • 用户不用关心底层 TCP、粘包、解析,只用写业务

用户只需要关心:收到一个 HttpRequest,回一个 HttpResponse。

2. 类结构

cpp 复制代码
class HttpServer
{
public:
  // 用户回调:输入 HttpRequest,输出 HttpResponse
  typedef std::function<void(const HttpRequest&, HttpResponse*)> HttpCallback;

  HttpServer(EventLoop* loop, const InetAddress& listenAddr, ...);

  void setHttpCallback(HttpCallback cb); // 设置业务回调
  void setThreadNum(int numThreads);     // 设置线程数
  void start();                          // 启动服务器

private:
  // 内部回调
  void onConnection(...);   // 连接建立/断开
  void onMessage(...);      // 消息到达 → 解析 HTTP
  void onRequest(...);      // 解析完成 → 调用用户回调

  TcpServer server_;         // 底层 TCP 服务器
  HttpCallback httpCallback_;// 用户业务回调
};

3. 核心:用户回调

cpp 复制代码
typedef std::function<void(
  const HttpRequest& req,   // 输入:解析好的请求
  HttpResponse* resp       // 输出:你要构造的响应
)> HttpCallback;

用户代码只需要写这个:

cpp 复制代码
void onHttpRequest(const HttpRequest& req, HttpResponse* resp)
{
  resp->setStatusCode(200);
  resp->setBody("Hello World");
}

**这就是全部!**底层 TCP、解析、发送,HttpServer 全部帮你搞定。

4. HttpServer 工作流程

cpp 复制代码
浏览器发送 HTTP 请求
     ↓
TcpServer 接收连接
     ↓
onMessage 收到数据
     ↓
HttpContext 解析(状态机)
     ↓
解析完成 → HttpRequest
     ↓
调用用户回调 httpCallback_
     ↓
用户填充 HttpResponse
     ↓
HttpResponse.appendToBuffer
     ↓
TcpConnection 发送回浏览器

5. HttpServer 内部组件关系

cpp 复制代码
HttpServer
   │
   ├─ TcpServer(底层网络)
   │
   ├─ 每个连接自带 HttpContext(解析)
   │
   └─ 给用户提供:HttpRequest → HttpResponse

6. 为什么 HttpServer 如此简单

因为:

  • TcpServer 负责网络
  • HttpContext 负责解析
  • HttpRequest/HttpResponse 负责数据结构
  • HttpServer 只负责把它们串起来

这就是模块化的威力!

二、 HttpServer.cc

先贴出完整代码,再逐部分解释:

cpp 复制代码
// Copyright 2010, Shuo Chen. 保留所有权利。
// http://code.google.com/p/muduo/
//
// 本源代码的使用受 BSD 许可证约束
// 可在 License 文件中找到许可证条款。

// 作者:陈硕 (chenshuo at chenshuo dot com)

#include "muduo/net/http/HttpServer.h"
#include "muduo/base/Logging.h"
#include "muduo/net/http/HttpContext.h"
#include "muduo/net/http/HttpRequest.h"
#include "muduo/net/http/HttpResponse.h"

using namespace muduo;
using namespace muduo::net;

namespace muduo
{
namespace net
{
namespace detail
{

// 默认 HTTP 回调:未找到资源,返回 404
void defaultHttpCallback(const HttpRequest&, HttpResponse* resp)
{
  resp->setStatusCode(HttpResponse::k404NotFound);
  resp->setStatusMessage("Not Found");
  resp->setCloseConnection(true);
}

}  // namespace detail
}  // namespace net
}  // namespace muduo

// 构造函数:初始化底层 TcpServer,设置默认回调
HttpServer::HttpServer(EventLoop* loop,
                       const InetAddress& listenAddr,
                       const string& name,
                       TcpServer::Option option)
  : server_(loop, listenAddr, name, option),
    httpCallback_(detail::defaultHttpCallback)
{
  // 设置 TCP 连接回调
  server_.setConnectionCallback(
      std::bind(&HttpServer::onConnection, this, _1));
  // 设置 TCP 消息回调
  server_.setMessageCallback(
      std::bind(&HttpServer::onMessage, this, _1, _2, _3));
}

// 启动 HTTP 服务器
void HttpServer::start()
{
  LOG_WARN << "HttpServer[" << server_.name()
    << "] starts listening on " << server_.ipPort();
  server_.start();
}

// TCP 连接建立/断开时调用
void HttpServer::onConnection(const TcpConnectionPtr& conn)
{
  // 连接建立时,为连接绑定一个 HttpContext 上下文(用于解析 HTTP)
  if (conn->connected())
  {
    conn->setContext(HttpContext());
  }
}

// TCP 消息到达:接收数据并解析 HTTP 请求
void HttpServer::onMessage(const TcpConnectionPtr& conn,
                           Buffer* buf,
                           Timestamp receiveTime)
{
  // 从连接上下文取出 HttpContext
  HttpContext* context = boost::any_cast<HttpContext>(conn->getMutableContext());

  // 解析 HTTP 请求,解析失败返回 400 错误
  if (!context->parseRequest(buf, receiveTime))
  {
    conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
    conn->shutdown();
  }

  // 如果解析完成一个完整请求
  if (context->gotAll())
  {
    // 交给业务逻辑处理
    onRequest(conn, context->request());
    // 重置上下文,准备解析下一个请求(长连接)
    context->reset();
  }
}

// 处理 HTTP 请求:构造响应并发送
void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req)
{
  // 根据请求头判断是否需要关闭连接
  const string& connection = req.getHeader("Connection");
  bool close = connection == "close" ||
    (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive");

  // 创建 HTTP 响应对象
  HttpResponse response(close);
  // 调用用户注册的业务回调
  httpCallback_(req, &response);

  // 将响应序列化到缓冲区
  Buffer buf;
  response.appendToBuffer(&buf);
  // 发送响应
  conn->send(&buf);

  // 如果是短连接,发送完毕后关闭
  if (response.closeConnection())
  {
    conn->shutdown();
  }
}

1. 一句话总结

HttpServer 不做网络、不做解析,只做 "调度"

  • 网络:交给 TcpServer
  • 解析:交给 HttpContext
  • 数据:交给 HttpRequest/HttpResponse
  • 它只负责:收到数据 → 解析 → 调用用户 → 发回响应

2. 默认回调

cpp 复制代码
void defaultHttpCallback(...)
{
  resp->setStatusCode(404);
  resp->setStatusMessage("Not Found");
}

作用:访问不存在的页面 → 返回 404

3. 构造函数 HttpServer::HttpServer ()

cpp 复制代码
HttpServer::HttpServer(...)
  : server_(loop, ...),    // 内部创建TcpServer
    httpCallback_(defaultHttpCallback)
{
  // 监听连接建立/断开
  server_.setConnectionCallback(&HttpServer::onConnection);

  // 监听消息到达
  server_.setMessageCallback(&HttpServer::onMessage);
}

作用:把 TcpServer 的事件,全部接管过来自己处理。

4. 连接建立:onConnection ()

cpp 复制代码
void HttpServer::onConnection(const TcpConnectionPtr& conn)
{
  if (conn->connected())
  {
    // 给这个连接绑定一个 HttpContext(解析器)
    conn->setContext(HttpContext());
  }
}

关键点:一个 TCP 连接 → 绑定一个 HttpContext 解析器长连接多条请求,复用同一个解析器。

5. 消息到达:onMessage ()

cpp 复制代码
void HttpServer::onMessage(...)
{
  // 取出连接绑定的解析器
  HttpContext* context = ...conn->getMutableContext();

  // 1. 解析 HTTP 请求
  if (!context->parseRequest(buf, receiveTime))
  {
    // 解析失败 → 400 错误
    conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
    conn->shutdown();
  }

  // 2. 如果解析完成
  if (context->gotAll())
  {
    // 交给用户业务处理
    onRequest(conn, context->request());
    // 重置解析器,准备下一条请求
    context->reset();
  }
}

这就是 HTTP 解析的完整流程:

  1. 从 TCP 连接拿解析器 HttpContext
  2. 把 Buffer 数据交给解析器
  3. 解析完成 → 调用业务
  4. 重置解析器 → 长连接继续用

6. 请求处理:onRequest ()

cpp 复制代码
void HttpServer::onRequest(...)
{
  // 判断是否长连接
  bool close = ...;

  // 创建 HTTP 响应
  HttpResponse response(close);

  // ------------------------ 调用用户代码 ------------------------
  httpCallback_(req, &response);

  // 把响应转成 Buffer
  Buffer buf;
  response.appendToBuffer(&buf);

  // 发送给客户端
  conn->send(&buf);

  // 如果短连接,发送完关闭
  if (response.closeConnection())
    conn->shutdown();
}

这里做了 4 件事:

  1. 判断连接是否保持(长连接)
  2. 创建 HttpResponse
  3. 调用用户回调(你写的业务逻辑)
  4. 发送响应,关闭或保持连接

7. HttpServer 工作全流程图

cpp 复制代码
浏览器请求
    ↓
TcpConnection 收到数据
    ↓
onMessage()
    ↓
HttpContext 解析(状态机)
    ↓
解析完成 → HttpRequest
    ↓
onRequest()
    ↓
用户回调:你处理 req → resp
    ↓
HttpResponse 打包成协议
    ↓
发送回浏览器
    ↓
短连接关闭 / 长连接等待下一条

8. HttpServer 最核心的作用

  • 封装 TcpServer,提供 HTTP 专用接口
  • 自动管理 HttpContext,完成协议解析
  • 用户只写业务:HttpRequest → HttpResponse
相关推荐
郝学胜-神的一滴2 小时前
从线程栈到表达式求值:栈结构的核心应用与递归实现
开发语言·数据结构·c++·算法·面试·职场和发展·软件工程
charlie1145141912 小时前
通用GUI编程技术——Win32 原生编程实战(十八)——GDI 设备上下文(HDC)完全指南
开发语言·c++·ide·学习·visual studio·win32
tankeven2 小时前
HJ150 全排列
c++·算法
Q741_1472 小时前
每日一题 力扣 2946. 循环移位后的矩阵相似检查 力扣 155. 最小栈 数学 数组 模拟 C++ 题解
c++·算法·leetcode·矩阵·模拟·数组·
2301_810160952 小时前
C++中的状态模式
开发语言·c++·算法
AIminminHu2 小时前
OpenGL渲染与几何内核那点事-项目实践理论补充(一-1-(2):看似“老派”的 C++ 底层优化,恰恰是这些前沿领域最需要的基础设施)
开发语言·c++
qq_466302453 小时前
vs2022 mn矩阵运算 加减乘除
c++·算法·矩阵
励志的小陈3 小时前
C++入门
开发语言·c++
繁星星繁3 小时前
Python基础语法(一)
c++·笔记·python