muduo的http库剖析

从零开始学写HTTP服务器(六)使用muduo网络库 muduo实现简单的HttpServer 阅读详情

    本文地址:(LYanger的博客:http://blog.youkuaiyun.com/freeelinux/article/details/53643802)


一:http协议

    首先看一下http request:

  • request line + header + body (header分为普通报头,请求报头与实体报头)
  • header与body之间有一空行(CRLF)
    请求方法有:GET、POST、HEAD、PUT、DELETE等
    协议版本:1.0、1.1

    详细知识参见这篇博客: http必知必会
    或者有关面试的http知识见这篇博客: http面试必知必会
    http断点续传原理: http断点续传原理

二:muduo库http测试以及抓包

    muduo库的http库自带了一个http_server的测试用例,即muduo/net/http/tests/HttpServer.cc,我们将它拿来测试一下,并用wireshark抓包分析http协议。
    编译时需要加-lmudo_base -lmuduo_net -lmuduo_http -lpthread选项。在这里就不上代码了,后面会有分析,我们主要先抓包分析协议。
    
    虚拟机运行该测试用例,使用tcpdump输入:

      tcpdump -Xvvenn -i eth1 tcp[20:2]=0x4745 or tcp[20:2]=0x4854 -s 80 -w tcpdump.cap
    
    开始捕获,浏览器输入虚拟机地址和端口号,然后收到响应,截图如下:

   
    我们将保存的.cap文件使用windows的wireshark打开,关于wireshark怎么分析可以参考: Wireshark数据抓包教程之认识捕获分析数据包
    
    如图,我们不管别的,点击上方选项:分析->追踪流->TCP流就可以得到:


    这样我们就可以窥探所有的http数据报内容了,对比第一张图网页中显示的内容,我们可以总结一下:
    先看 GET请求:使用HTTP 1.1版本。服务器地址192.168.33.147,端口8000。使用keep-alive长链接。Cache-Control是用来控制的,常见的取值有private、no-cache、
max_age等,如果指定max-age值,那么在此值的时间内就不会重新访问服务器,数据由缓存直接返回,单位为秒。
    常用请求头:
  • Accept:浏览器可接受的媒体类型(MIME)类型
  • Accept-Language:浏览器所希望的语言种类
  • Accept-Encoding:浏览器能够解码的方法,如,gzip,deflate等
  • User-Agent:告诉HTTP服务器,客户端使用的操作系统和浏览器的版本和名称
  • Connection:表示是否需要持久连接,Keep-Alive表示长连接,close表示短连接
    
    再看 HTTP响应包:status line+header+body(header分为普通报头,响应报头与实体报头),header与body之间有一空行(CRLF)。
    状态响应码:
  • 1xx    提示信息-表示请求已被成功接收,继续处理
  • 2xx    成功-表示请求已被成功接收,理解,接受
  • 3xx    重定向-要完成请求必须进行更进一步的处理
  • 4xx    客户端错误-请求有语法错误或请求无法实现
  • 5xx    服务器端错误-服务器执行一个有效请求失败

三:muduo的http库剖析

    muduo的http库一共有四个类,HttpRequest(http请求类封装)、HttpResponse(http响应类封装)、HttpContext(http协议解析类)、HttpServer(http服务器封装)。

在这里我们就拿出上文中例子的代码来剖析muduo的http库,实例代码:
#include <muduo/net/http/HttpServer.h>
#include <muduo/net/http/HttpRequest.h>
#include <muduo/net/http/HttpResponse.h>
#include <muduo/net/EventLoop.h>
#include <muduo/base/Logging.h>

#include <iostream>
#include <map>

using namespace muduo;
using namespace muduo::net;

extern char favicon[555];
bool benchmark = false;
//响应回调函数
void onRequest(const HttpRequest& req, HttpResponse* resp)
{
  std::cout << "Headers " << req.methodString() << " " << req.path() << std::endl;
  if (!benchmark)   //如果为真,打印头部
  {
    const std::map<string, string>& headers = req.headers();
    for (std::map<string, string>::const_iterator it = headers.begin();
         it != headers.end();
         ++it)
    {   
      std::cout << it->first << ": " << it->second << std::endl;
    }   
  }
  //如果路径为根路径
  if (req.path() == "/")
  {
  resp->setStatusCode(HttpResponse::k200Ok);  //状态码200
    resp->setStatusMessage("OK");   //ok
    resp->setContentType("text/html");  //html文本
    resp->addHeader("Server", "Muduo");   //增加头部
    string now = Timestamp::now().toFormattedString();   //生成时间戳
    resp->setBody("<html><head><title>This is title</title></head>"    //标题
        "<body><h1>Hello</h1>Now is " + now +    //内容
        "</body></html>");
  }
  else if (req.path() == "/favicon.ico")   //如果访问/favicon.ico路径,响应发送一张图片
  {
    resp->setStatusCode(HttpResponse::k200Ok);
    resp->setStatusMessage("OK");
    resp->setContentType("image/png");
    resp->setBody(string(favicon, sizeof favicon));
  }
  else if (req.path() == "/hello")  //访问“/hello"路径,省略
  {
    ...
  }
  else
  {
    resp->setStatusCode(HttpResponse::k404NotFound);   //如果都不是,出现我们没有设置的路径,那么返回404,找不到
    resp->setStatusMessage("Not Found");
    resp->setCloseConnection(true);  //断开连接
  }
}
int main(int argc, char* argv[])
{
  int numThreads = 0;
  if (argc > 1)
  {
    benchmark = true;   //用来标志服务器是否打印header信息
    Logger::setLogLevel(Logger::WARN);
    numThreads = atoi(argv[1]);  //多线程数,如果为0,则不启动多线程
  }
  EventLoop loop;
  HttpServer server(&loop, InetAddress(8000), "dummy");  //HttpServer类,客端可以以基于对象的方式把它包含起来
  server.setHttpCallback(onRequest);   //设置响应回调
  server.setThreadNum(numThreads); //可能启动多线程
  server.start();   //启动
  loop.loop();  //循环等待
}
//这是一个图片数组,省略了一部分
char favicon[555] = {
   '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA',
    ...
}

上述程序就是前文中的程序,结果前文中使用wireshark已经分析过了。

我们来过一下流程,首先客端创建一个HttpServer对象,它的成员是这样的:
class HttpServer : boost::noncopyable
{
 public:
  typedef boost::function<void (const HttpRequest&,
                                HttpResponse*)> HttpCallback;
  HttpServer(EventLoop* loop,
             const InetAddress& listenAddr,
             const string& name,
             TcpServer::Option option = TcpServer::kNoReusePort);

  ~HttpServer();  // force out-line dtor, for scoped_ptr members.
  EventLoop* getLoop() const { return server_.getLoop(); }
  /// Not thread safe, callback be registered before calling start().
  void setHttpCallback(const HttpCallback& cb);
  void setThreadNum(int numThreads);
  void start();
 private:
  void onConnection(const TcpConnectionPtr& conn);
  void onMessage(const TcpConnectionPtr& conn,
                 Buffer* buf,
                 Timestamp receiveTime);
  void onRequest(const TcpConnectionPtr&, const HttpRequest&);

  TcpServer server_;    //http服务器也是一个Tcp服务器,所以包含一个TcpServer
  HttpCallback httpCallback_;   //在处理http请求时(即调用onRequest)的过程中回调此函数,对请求进行具体的处理。
};
    作为一个暴露给外部客端的类, HttpServer就是一个服务器的封装,由于http协议底层使用tcp协议,所以它包含了一个TcpServer。并且向客户提供了一个回调函数的接口,当服务器收到http请求时,调用客户端的处理函数进行处理,该函数必须在start()之前设定。
    HttpServer支持多线程,也可以使用单线程,同样setThreadNum()函数必须在start()函数调用之前被调用。

    HttpServer的构造函数是这样的:
HttpServer::HttpServer(EventLoop* loop,
                       const InetAddress& listenAddr,
                       const string& name,
                       TcpServer::Option option)
  : server_(loop, listenAddr, name, option),
    httpCallback_(detail::defaultHttpCallback)
{
  //连接到来回调该函数
  server_.setConnectionCallback(
      boost::bind(&HttpServer::onConnection, this, _1));  
  //消息到来回调该函数
  server_.setMessageCallback(
      boost::bind(&HttpServer::onMessage, this, _1, _2, _3));
}
初始化TcpServer,并将HttpServer的回调函数传给TcpServer。主要有两个函数:

其一是onConenction()函数:

void HttpServer::onConnection(const TcpConnectionPtr& conn)
{
  if (conn->connected())
  {
    //构造一个http上下文对象,用来解析http请求
    conn->setContext(HttpContext()); //TcpConnection和一个HttpContext绑定,利用boost::any
  }
}
该函数为一个新的TcpConnection绑定一 个HttpContext对象,使用的是TcpConnection中的boost::any,绑定之后,HttpContext就相当于TcpConnection的成员了,TcpConection在MessageCallback中就可以随意的使用HttpContext对象了。

那么,HttpContext类是干什么的? 来看一下它的类:
class HttpContext : public muduo::copyable
{
 public:
  enum HttpRequestParseState  //解析请求状态的枚举常量
  {
    kExpectRequestLine,   //当前正处于解析请求行的状态
    kExpectHeaders,          //当前正处于解析请求头部的状态
    kExpectBody,               //当前正处于解析请求实体的状态
    kGotAll,                       //解析完毕
  };
  HttpContext()
    : state_(kExpectRequestLine)  //初始状态,期望收到一个请求行
  {
  }
  // default copy-ctor, dtor and assignment are fine
  // return false if any error
  bool parseRequest(Buffer* buf, Timestamp receiveTime);
  
  bool gotAll() const
  { return state_ == kGotAll; }

  //重置HttpContext状态,异常安全
  void reset()
  {
    state_ = kExpectRequestLine;
    HttpRequest dummy;   //构造一个临时空HttpRequest对象,和当前的成员HttpRequest对象交换置空,然后临时对象析构
    request_.swap(dummy);
  }

  const HttpRequest& request() const
  { return request_; }

  HttpRequest& request()
  { return request_; }

 private:
  bool processRequestLine(const char* begin, const char* end);

  HttpRequestParseState state_;   //请求的解析状态
  HttpRequest request_;    //http请求类
};
它就是一个http的上下文对象,实际上是一个状态机。针对http包进行处理,我们可以看出它在处理过程中在四种状态间切换:
  • kExpectRequestLine,  
  • kExpectHeaders,        
  • kExpectBody,    
  • kGotAll,                   
未收到http包是期待处理请求行,处理请求行之后处理头部,然后体部,最后gotall完成,不过中间可能会出错,到达不了这一步,会有相应的处理方案。它的函数待会再分析,因为它是HttpServer绑定的onMessage()回调函数会用到


其二是onMessage()函数:

void HttpServer::onMessage(const TcpConnectionPtr& conn,
                           Buffer* buf,
                           Timestamp receiveTime)
{
  //取出请求,mutable可以改变
  HttpContext* context = boost::any_cast<HttpContext>(conn->getMutableContext());

  //调用context的parseRequest解析请求,返回bool是否请求成功
  if (!context->parseRequest(buf, receiveTime))
  {
    conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");   //失败,发送400
    conn->shutdown();  //关闭连接
  }

  if (context->gotAll())  //请求成功
  {
    //调用onRequest
    onRequest(conn, context->request());
    //一旦请求处理完毕,重置context,因为HttpContext和TcpConnection绑定了,我们需要解绑重复使用。
    context->reset();
  }
}
没错,当TcpConnection中所拥有的连接有消息到来时,会调用它的messageCallback(应该是这名字,不过就是这个意思)函数,其实就是调用HttpServer的onMessage()函数。我们知道,我们之前在onConnection()函数中把HttpContext利用boost::any绑定给了TcpConnection,在onMessage()函数中我们就可以对TcpConnection使用HttpContext类来解析数据包了。

onMessage()函数首先调用HttpContext的parserRequset()函数解析请求,判断请求是否合法,进而选择关闭连接,或者处理请求。
HttpContex类的parserRequset()函数是这样实现的,利用状态机编程:
bool HttpContext::parseRequest(Buffer* buf, Timestamp receiveTime)
{
  bool ok = true;
  bool hasMore = true;
  while (hasMore)
  {
    //初始状态是处于解析请求行的状态,下一次循环不是该状态就不会进入,一般只进入一次
    if (state_ == kExpectRequestLine)
    {
      //首先查找\r\n,就会到GET / HTTP/1.1的请求行末尾
      const char* crlf = buf->findCRLF();
      if (crlf)
      {
        //解析请求行
        ok = processRequestLine(buf->peek(), crlf);
        if (ok)  //如果成功,设置请求行事件
        {
          //设置请求时间
          request_.setReceiveTime(receiveTime);
          //将请求行从buf中取回,包括\r\n
          buf->retrieveUntil(crlf + 2);
          state_ = kExpectHeaders;  //将Httpontext状态改为KexpectHeaders状态
        }
        else
        {
          hasMore = false;
        }
      }
      else
      {
        hasMore = false;
      }
    }
    else if (state_ == kExpectHeaders)  //处于Header状态
    {
      const char* crlf = buf->findCRLF();
      if (crlf)
      {
        const char* colon = std::find(buf->peek(), crlf, ':');  //查找:
        if (colon != crlf)
        {
          //找到添加头部,加到map容器
          request_.addHeader(buf->peek(), colon, crlf);
        }
        else
        {
          // empty line, end of header
          // FIXME:
          state_ = kGotAll;  //一旦请求完毕,再也找不到':'了,状态改为gotall状态,循环退出
          hasMore = false;
        }
        buf->retrieveUntil(crlf + 2);  //请求完毕也把crlf取回
      }
      else
      {
        hasMore = false;
      }
    }
    else if (state_ == kExpectBody)
    {
      // FIXME:
    }
  }
  return ok;
}
它先是解析请求行,如果有错has_more为false会跳出循环,后面代码解析所有的头部数据,有错也会跳出循环。
解析请求行是这样的:
bool HttpContext::processRequestLine(const char* begin, const char* end)
{
  bool succeed = false;
  const char* start = begin;
  const char* space = std::find(start, end, ' ');   //查找空格
  //格式 : GET / HTTP/1.1
  //找到GET并设置请求方法
  if (space != end && request_.setMethod(start, space))
  {
    start = space+1;
    space = std::find(start, end, ' ');  //再次查找
    if (space != end)  //找到
    {
      const char* question = std::find(start, space, '?');
      if (question != space)  //找到了'?',说明有请求参数
      {
        //设置路径
        request_.setPath(start, question);
        //设置请求参数
        request_.setQuery(question, space);
      }
      else
      {
        //没有找到只设置路径
        request_.setPath(start, space);
      }
      start = space+1;

      //查找有没有"HTTP/1."
      succeed = end-start == 8 && std::equal(start, end-1, "HTTP/1.");
      if (succeed)  //如果成功,判断是采用HTTP/1.1还是HTTP/1.0
      {
        if (*(end-1) == '1')
        {
          request_.setVersion(HttpRequest::kHttp11);
        }
        else if (*(end-1) == '0')
        {
          request_.setVersion(HttpRequest::kHttp10);
        }
        else
        {
          succeed = false;  //请求行失败
        }
      }
    }
  }
  return succeed;
}
好的,请求行一旦解析完毕,如果失败会关闭连接,成功的化onMessage()函数会继续进行,开始执行onRequest()函数处理请求:
void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req)
{
  //取出头部
  const string& connection = req.getHeader("Connection");
  // 如果connection为close或者1.0版本不支持keep-alive,标志着我们处理完请求要关闭连接
  bool close = connection == "close" ||
    (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive");
  //使用close构造一个HttpResponse对象,该对象可以通过方法.closeConnection()判断是否关闭连接
  HttpResponse response(close);
  //typedef boost::function<void (const HttpRequest&, HttpResponse*)> HttpCallback;
  //执行用户注册的回调函数
  httpCallback_(req, &response);
  Buffer buf;   //用户处理后的信息,追加到缓冲区
  response.appendToBuffer(&buf);
  conn->send(&buf);  //发送数据
  if (response.closeConnection())  //如果关闭
  {
    conn->shutdown();  //关了它
  }
}
这里有又一个新的 HttpResponse对象,这个类只有一个.h文件,我们来看一下:
class HttpRequest : public muduo::copyable
{
 public:
  enum Method  //请求方法
  {
    kInvalid, kGet, kPost, kHead, kPut, kDelete
  };
  enum Version  //协议版本
  {
    kUnknown, kHttp10, kHttp11
  };

  HttpRequest()  
    : method_(kInvalid),
      version_(kUnknown)
  {
  }

  //设置版本
  void setVersion(Version v)
   {
    version_ = v;
  }

  Version getVersion() const
  { return version_; }

  //设置方法,
  bool setMethod(const char* start, const char* end)
  {
    assert(method_ == kInvalid);
    //使用字符串首尾构造string,不包括尾部,如char *s="123", string s=(s,s+3),则s输出为123
    string m(start, end);
    if (m == "GET")
    {
      method_ = kGet;
    }
    else if (m == "POST")
    {
      method_ = kPost;
    }
    else if (m == "HEAD")
    {
      method_ = kHead;
    }
    else if (m == "PUT")
    {
      method_ = kPut;
    }
    else if (m == "DELETE")
    {
      method_ = kDelete;
    }
    else
    {
      method_ = kInvalid;
    }
    return method_ != kInvalid;
  }

  //返回请求方法
  Method method() const
  { return method_; }

  //请求方法转换成字符串
  const char* methodString() const
  {
    const char* result = "UNKNOWN";
    switch(method_)
    {
      case kGet:
        result = "GET";
        break;
      case kPost:
        result = "POST";
        break;
      case kHead:
        result = "HEAD";
        break;
      case kPut:
        result = "PUT";
        break;
      case kDelete:
        result = "DELETE";
        break;
      default:
        break;
    }
    return result;
  }

  //设置路径
  void setPath(const char* start, const char* end)
  {
    path_.assign(start, end);
  }

  const string& path() const
  { return path_; }

  //
  void setQuery(const char* start, const char* end)
  {
    query_.assign(start, end);
  }

  const string& query() const
  { return query_; }

  //设置接收时间
  void setReceiveTime(Timestamp t)
  { receiveTime_ = t; }

  Timestamp receiveTime() const
  { return receiveTime_; }

  //添加头部信息,客户传来一个字符串,我们把它转化成field: value的形式
  void addHeader(const char* start, const char* colon, const char* end)
  {
    string field(start, colon);  //header域
    ++colon;
    //去除左空格
    while (colon < end && isspace(*colon))
    {
      ++colon;
    }
    string value(colon, end);   //heade值
    //去除右空格,如果右边有空格会一直resize-1
    while (!value.empty() && isspace(value[value.size()-1]))
    {
      value.resize(value.size()-1);
    }
    //std::map<string, string> headers_;  
    headers_[field] = value;
  }

  //根据头域返回值
  string getHeader(const string& field) const
  {
    string result;
    std::map<string, string>::const_iterator it = headers_.find(field);
    if (it != headers_.end())
    {
      result = it->second;
    }
    return result;
  }

  //返回头部
  const std::map<string, string>& headers() const
  { return headers_; }

  //交换
  void swap(HttpRequest& that)
  {
    std::swap(method_, that.method_);
    path_.swap(that.path_);
    query_.swap(that.query_);
    receiveTime_.swap(that.receiveTime_);
    headers_.swap(that.headers_);
  }

 private:
  Method method_;      //请求方法
  Version version_;      //请求版本
  string path_;             //请求路径
  string query_;           //请求参数
  Timestamp receiveTime_;    //请求接收时间
  std::map<string, string> headers_;    //header列表
};
这个类的作用就是示例代码中那样,设置响应的各种信息,包括头部,体部,示例代码中这样用的:
  resp->setStatusCode(HttpResponse::k200Ok);  //状态码200
    resp->setStatusMessage("OK");   //ok
    resp->setContentType("text/html");  //html文本
    resp->addHeader("Server", "Muduo");   //增加头部
    string now = Timestamp::now().toFormattedString();   //生成时间戳
    resp->setBody("<html><head><title>This is title</title></head>"    //标题
        "<body><h1>Hello</h1>Now is " + now +    //内容
        "</body></html>");
然后onRequest()函数这样执行的:
void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req)
{
  //取出头部
  const string& connection = req.getHeader("Connection");
  // 如果connection为close或者1.0版本不支持keep-alive,标志着我们处理完请求要关闭连接
  bool close = connection == "close" ||
    (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive");
  //使用close构造一个HttpResponse对象,该对象可以通过方法.closeConnection()判断是否关闭连接
  HttpResponse response(close);
  //typedef boost::function<void (const HttpRequest&, HttpResponse*)> HttpCallback;
  //执行用户注册的回调函数
  httpCallback_(req, &response);
  Buffer buf;   //用户处理后的信息,追加到缓冲区
  response.appendToBuffer(&buf);
  conn->send(&buf);  //发送数据
  if (response.closeConnection())  //如果关闭
  {
    conn->shutdown();  //关了它
  }
}


        
    

也就是说使用HttpResponse类设置完响应各种信息之后,我们就可以把他发回给用户了。如果使用短连接,那就关掉该连接即可。


muduo的http库的代码到这里就暂时结束了,要是想到什么我会再补充。


今天12月15号,离来年三月春招还有两个半月,这两个半月一定努力,向某人证明自己。





muduo的inspect库以及TCP的Keep-Alive时间分析 一:源码分析     今天剖析muduo inspect库。muduo_inspect库通过HTTP的方式为服务器提供监控接口。比如提供以下功能: 接收了多少个TCP连接当前有多少个活动连接一共响应了多少次请求每次请求的平均响应时间为多少ms...     inspect库主要有Inspector类组成,它包含了一个HttpServer对象,并同过ProcessInspector类返 阅读详情

相关推荐

从零构建C++ Web服务器:基于Muduo思想实现HTTP服务与并发处理

网络编程是构建现代互联网服务的基石,其核心在于理解服务器如何高效处理海量并发连接。其基本原理是通过Socket建立通信链路,并基于TCP/IP协议进行可靠的数据传输。为了提升性能,现代服务器普遍采用I/O多路复用(如epoll)与非阻塞I/O相结合的事件驱动模型,这能有效减少线程资源消耗,支撑高并发场景。这种技术的核心价值在于,它使得单台服务器能够同时服务成千上万的客户端连接,是支撑电商、社交、云计算等大规模在线应用的关键。在工程实践中,主从Reactor多线程架构是一种经典设计模式,它将连接接收与请求处理

weixin_31815843的博客 322

muduo学习笔记:net部分之Http-协议简介

HTTP协议(HyperText Transfer Protocol,超文本传输协议)目前是互联网上应用最为广泛的一种网络传输协议,基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等),最新已经发展到基于UDP/QUICK的HTTP/3版本,目前协议版本多使用1.1。另外,本文不介绍HTTPS基于SSL/TLS加密。 HTTP协议是基于文本的,也就是TCP传输主要是文本(数据部分可能是二进制数据),HTTP消息分为请求Request、响应Response两种。HTTP的请求由客户端

热爱生活,忠于自己 1041

(源码)基于muduo网络库的简单HTTP服务器.zip

# 基于muduo网络库的简单HTTP服务器 ## 项目简介 这是一个基于muduo网络库的简单HTTP服务器,用于处理HTTP请求并响应。它使用muduo库中的事件驱动模型,通过命令行参数配置服务器参数,如线程数、端口号、日志配置等。服务器能够处理静态文件请求、执行CGI脚本,并响应HTTP请求。 ## 主要特性和功能 1. 基于muduo网络库使用muduo库的事件驱动模型,实现高性能的网络处理。 2. 命令行参数配置通过命令行参数设置服务器参数,包括线程数、端口号、日志配置等。 3. 静态文件响应服务器能够响应静态文件的请求,如HTML、图片等。 4. CGI脚本执行服务器支持执行CGI脚本,将客户端发送的POST数据传递给CGI脚本,并将结果返回给客户端。 5. 日志记录使用自定义的日志记录系统,支持不同级别的日志记录,方便调试和排查问题。 6. 多线程处理采用线程池和非阻塞socket,支持并发处理多个请求。

muduo学习笔记:net部分之Http--HttpRequest、HttpResponse 和 HttpContext

前文[【muduo学习笔记:net部分之Http-协议简介】]简单介绍了HTTP的协议,本文使用muduo网络库简单实现HTTP的请求体和响应体。 客户端发送请求,通过muduo库之后服务端收到的数据存放于`Buffer`中,之后解析成`HttpRequest`请求对象,再创建一个`HttpResponse`响应对象并格式化成`Buffer`返回给客户端。服务端解析客户端请求的Buffer使用`HttpContext`类。

热爱生活,忠于自己 2041

HBuilderx连接微信开发者工具

系列文章目录 文章目录系列文章目录前言一、环境1.HBuilerx 工具2.微信开发者工具二、关联微信开发者工具1.HBuilderx新建项目2.关联微信开发者工具3.运行微信小程序出现异常解决方法3.最终效果总结 前言 使用HBuilderx工具关联微信开发者工具,进行小程序开发 提示:以下是本篇文章正文内容,下面案例可供参考 一、环境 1.HBuilerx 工具 HBuilderx 2.微信开发者工具 微信开发者工具 二、关联微信开发者工具 1.HBuilderx新建项目 2.关联微信开发者工具

拥有必珍惜 3078

stc8g1k08硬件iic读取aht20温湿度及0.91寸oled显示

使用stc8g1k08读取aht20温湿度及0.91寸oled显示。

qq_61688416的博客 2772

muduo网络库学习之muduo_http 库涉及到的类

1、http request: request line + header + body (header分为普通报头,请求报头与实体报头) header与body之间有一空行(CRLF) 请求方法有: Get, Post, Head, Put, Delete等 协议版本1.0、1.1 常用请求头 Accept:浏览器可接受的

Meditation 6125

基于Labview2012实现的双通道信号源(课程设计)

双通道信号源,产生8种波形,能进行调制,带信号幅度与频率扫描功能,波形可存储与导入

qq_40617082的博客 1461

muduo项目部分2---Http协议模块 + 代码

Http协议模块分为一个大模块,里面整合了五个子模块。四个子模块:Util模块: 这个模块是⼀个⼯具模块,主要提供HTTP协议模块所⽤到的⼀些⼯具函数,⽐如url编解码,⽂件读 写....等。HttpRequest模块: 这个模块是HTTP请求数据模块,⽤于保存HTTP请求数据被解析后的各项请求元素信息。HttpResponse模块: 这个模块是HTTP响应数据模块,⽤于业务处理后设置并保存HTTP响应数据的的各项元素信息,最终 会被按照HTTP协议响应格式组织成为响应信息发送给客⼾端。

m0_74099572的博客 1075

智能座舱测试工程师必看:从零搭建自动化测试框架的5个实战技巧

本文为智能座舱测试工程师提供从零搭建自动化测试框架的5个实战技巧,涵盖环境搭建、ADB高级应用、Python脚本工程化、Monkey测试优化及性能调优。通过ADB深度操作和Python脚本封装,帮助测试人员构建高可复用的智能座舱测试解决方案,显著提升测试效率与问题发现率。

python9snake的博客 639

腾讯、飞书等在线表格自动化编辑--python

在线文档自动化处理数据

qq_32828053的博客 2万+

实战项目:基于主从Reactor模型实现高并发服务器

仿muduo库One Thread One Loop式主从Reactor模型实现⾼并发服务器: 通过模拟实现的⾼并发服务器组件,可以简洁快速的完成⼀个⾼性能的服务器搭建。并且,通过组件内提供的不同应⽤层协议⽀持,也可以快速完成⼀个⾼性能应⽤服务器的搭建(项⽬中提供HTTP协议组件的⽀持)。项目主要实现的是⼀个⾼并发服务器组件,因此当前的项⽬中并不包含实际的业务内容。

小张的博客 2229

陀螺仪与加速度计的姿态融合——互补滤波

本篇文章我们来讲讲如何将陀螺仪和加速度计的数据结合起来,获取更准确的姿态数据,使用的是互补滤波的方法。

小白白学电子 2万+

长文梳理Muduo库核心代码及优秀编程细节剖析

长文梳理Muduo库核心代码(Multi-Reactor架构代码)及优秀编程细节思想剖析。

T_Solotov的博客 1万+

Vue3 - 实现集成配置百度语音识别转文字,长按或开启录音并将录音文件实时转换为文字,上传音频文件利用百度语音识别API转换为文本并展示(vue3百度智能云API实现上传录音文件并转换成文字案例)

vue3对接百度智能云语音识别,vue3 h5移动端网页中实现语音识别,百度语音识别录音转文字_百度智能云,vue3如何使用百度语音识别,如何将语音转文字,使用vue3实现录音并将录音转换为文字,vue3如何实现语音输入功能功能,vue3集成百度智能云API实现录音转文字详细教程完整示例代码demo,VUE3使用百度语音识别语音转文字,vue调用百度语音识别,vue3百度语音识别文字并展示功能,vue3免费语音转文本api,百度语音识别申请配置教程,Vue3项目配置自定义界面百度语音识别转文字和原生使用方式

🏆 前端领域优质创作者 2730

路由三大分类:直连路由、静态路由、动态路由

直连路由、静态路由和动态路由各有其独特的特点和适用场景。直连路由适用于简单的直接连接网络,静态路由提供了精确的路径控制,而动态路由则在大型复杂网络中展现出强大的适应性和自动化能力。了解和掌握这三种路由类型的配置和管理,对于网络管理员来说,是确保网络高效、安全运行的重要技能。

网络技术联盟站 4699

[muduo网络库]——muduo库的Reactor模型(剖析muduo网络库核心部分、设计思想)

muduo 是由陈硕大佬个人开发的 TCP 网络库,本专栏使用c++11重构了Muduo库中核心的Multi-Reactor架构,剖析大佬核心的代码设计思想,希望能够理清自己的思路,也希望能够帮助到大家。

m0_73537205的博客 2032

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

基于muduo库来实现翻译服务器

Muduo是一个基于C++11的高性能TCP网络库,专为Linux平台设计。它封装了epoll、事件驱动和多线程等底层细节,提供简单易用的接口,使开发者能快速构建高并发服务器。核心特性包括:事件驱动模型(基于epoll)、多线程Reactor架构、TCP服务器/客户端支持、HTTP服务器、定时器和异步日志等。Muduo采用主从Reactor模式,主线程负责accept连接,子线程处理I/O操作,每个EventLoop绑定固定线程保证线程安全。典型应用场景包括即时通讯、物联网接入、HTTP API服务和游戏网

m0_75006599的博客 997

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

muduo_inspect库源码分析(41)

muduo_inspect库通过HTTP方式为服务器提供监控接口 接受了多少个TCP连接 当前有多少个活动连接 一共响应了多少次请求 每次请求的平均响应时间多少毫秒 。。。 Inspector     // 包含了一个HttpServer对象 ProcessInspector // 通过ProcessInfo返回进程信息 ProcessInfo // 获取进程相关信息

Riak, Spark, Golang, Erlang, 云存储, 云计算, 数据挖掘 1791

【c++】muduo库(二)网络基础知识

I/O 处理流fd→Poller活跃事件 →→ 用户回调(读操作使用Buffer,写操作触发send/flush,可能注册/取消定时器)定时任务流TimerQueue通过timerfd触发 → 回调在所属EventLoop线程执行跨线程任务流runInLoop写入eventfd唤醒目标EventLoop→ 保证任务在正确线程执行 → 减少锁竞争。

Edddddddddy的博客 759

从TCP字节流到HttpRequest:muduo HTTP解析状态机详解

在TCP网络编程中,粘包与半包问题几乎无法避免:一次读事件可能拿到多个请求,也可能一个请求被拆成多个TCP包。要稳定地将字节流还原为结构化的HTTP请求,通常需要借助有限状态机,按“请求行→请求头→请求体”的顺序逐级推进,同时与缓冲区(Buffer)紧密配合,以支持“能解析多少就解析多少”的流式处理。这种设计不仅有效解决半包等待与粘包切分问题,还能实现零拷贝的高效解析,是网络库与HTTP服务等场景下常见的协议解析范式。muduo作为一款高性能C++网络库,将HTTP解析独立封装为HttpContext类,内

weixin_32576389的博客 182

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

摘要:HttpContext是Muduo网络库中的HTTP协议解析器,负责将TCP字节流解析为HttpRequest对象。它采用状态机模式处理HTTP请求,包含4个解析状态:请求行、请求头、请求体和完成状态。核心功能包括processRequestLine()解析请求行、parseRequest()驱动状态机进行整体解析,并支持长连接复用。该设计有效解决了TCP粘包问题,确保即使数据分多次到达也能正确解析完整请求。HttpContext作为TcpConnection和用户处理逻辑之间的桥梁,实现了HTTP协

m0_62807361的博客 328

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

本文介绍了muduo网络库中的HttpServer实现。HttpServer是基于TcpServer封装的HTTP专用服务器,主要特性包括:1) 自动处理HTTP协议解析和响应构建;2) 提供简洁的回调接口,用户只需处理HttpRequest并填充HttpResponse;3) 内部通过TcpServer处理网络通信,HttpContext完成协议解析;4) 支持长连接和短连接。实现上采用模块化设计:TcpServer负责网络、HttpContext负责解析、HttpRequest/Response负责数据

m0_62807361的博客 401

002 仿muduo库实现高性能服务器组件_整体框架

本文不会包含任何项目模块的代码,旨在向你介绍项目具体分为哪几个模块,考虑到还没有涉及任何模块的学习,因此本文主要是为了让你写此项目的时候有一个初步印象,所以本文也不会涉及对各个模块深度剖析。

Moonnight_bit的博客 1126

解析muduo源码之 HttpRequest.h

HttpRequest.h 是 muduo 网络库中处理 HTTP 请求的核心头文件,主要功能是封装和存储解析后的 HTTP 请求信息。该文件定义了 HTTP 请求方法(GET/POST 等)和版本(HTTP/1.0/1.1)的枚举类型,并通过私有成员存储请求方法、路径、查询参数、接收时间和请求头等信息。核心功能包括设置/获取请求方法和版本、添加/获取请求头、交换数据等操作。该类作为 HTTP 请求的"容器",将请求报文解析为 C++ 对象,但不处理网络 IO,便于用户回调函数获取请求信

m0_62807361的博客 224

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

本文介绍了muduo网络库中的HttpResponse类实现。该类用于构造HTTP响应报文,包含状态码、响应头和响应体,并提供了将这些内容序列化成标准HTTP格式的功能。核心方法appendToBuffer()将响应按HTTP协议格式拼接成状态行、响应头、空行和响应体,写入Buffer用于发送。类设计考虑了长/短连接处理,自动添加Content-Length等必要头信息。该类与HttpRequest配合,完成HTTP请求-响应处理流程,是muduo实现HTTP服务器的重要组成部分。

m0_62807361的博客 445
上一篇: muduo库的Connector以及TcpClient的使用
下一篇: 完全二叉树统计节点个数【使用二分搜索】
FreeeLinux
博客等级 码龄11年 421粉丝 356原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值