从零开始学写HTTP服务器(六)使用muduo网络库


muduo源码中内嵌了一个简单的HTTP server程序,源码见muduo/net/http。看了源码之后受益匪浅。
muduo里面的HttpServer目前只支持GET和HEAD方法,获取资源的Content-Type在源代码中写死,本文主要就是添加了一个读取mime.type的功能。希望之后能继续扩展这个简单的HttpServer,支持CGI和POST。

(一)HttpServer

跟简单的echo server套路一样,首先定义一个HttpServer,它需要用EventLoop对象构造,包含一个TcpServer成员等。唯一的区别就是多了一个onRequest回调

//HttpServer.h

#ifndef __HTTPSERVER_H__
#define __HTTPSERVER_H__
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpServer.h>
#include <boost/noncopyable.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
#include <string>
#include <muduo/net/Buffer.h>
#include "HttpContext.h"
#include "HttpRequest.h"
#include "HttpResponse.h"
using namespace std;


class HttpServer : boost::noncopyable
{
    public:
    //http回调类型
    typedef boost::function<void (const HttpRequest&,
        HttpResponse*)> HttpCallback;

    //构造函数
    HttpServer(muduo::net::EventLoop* loop,
        const muduo::net::InetAddress& listenAddr);

    ~HttpServer();  // force out-line dtor, for scoped_ptr members.
    muduo::net::EventLoop* getLoop() const { return server_.getLoop(); }
    void setHttpCallback(const HttpCallback& cb)
    {
        httpCallback_ = cb;
    }
    void setThreadNum(int numThreads)
    {
        server_.setThreadNum(numThreads);
    }
    void start();

    private:
    //onConnection
    void onConnection(const muduo::net::TcpConnectionPtr &conn);
    //onMessage
    void onMessage(const muduo::net::TcpConnectionPtr&conn,
        muduo::net::Buffer*buf,
        muduo::Timestamp receiveTime);
    //+++++
    void onRequest(const muduo::net::TcpConnectionPtr&,const HttpRequest&);
    muduo::net::TcpServer server_;
    HttpCallback httpCallback_;
};
#endif
//HttpServer.cpp

#include "HttpServer.h"
#if 1
//默认HTTP回调,返回错误码
void defaultHttpCallback(const HttpRequest&, HttpResponse* resp)
{
#if 1
    resp->setStatusCode(HttpResponse::CODE_400);
    resp->setStatusMessage("Not Found");
    resp->setCloseConnection(true);
#endif
}
#endif


#if 1
//构造函数
HttpServer::HttpServer(muduo::net::EventLoop* loop,
    const muduo::net::InetAddress& listenAddr)
    : server_(loop, listenAddr, "MyHttpd"),httpCallback_(defaultHttpCallback)
{
    server_.setConnectionCallback(
        boost::bind(&HttpServer::onConnection, this, _1));

    server_.setMessageCallback(
        boost::bind(&HttpServer::onMessage, this, _1, _2, _3));
}
//析构函数
HttpServer::~HttpServer()
{
}
void HttpServer::start()
{
    LOG_WARN << "HttpServer[" << server_.name()
    << "] starts listenning on " << server_.ipPort();
    server_.start();
}
#endif

//新连接回调
void HttpServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
{
    if (conn->connected())
    {
        conn->setContext(HttpContext());
    }
}
//消息回调
void HttpServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
    muduo::net::Buffer* buf,
    muduo::Timestamp receiveTime)
{
    HttpContext*context=boost::any_cast<HttpContext>(conn->getMutableContext());
    //解析请求
    if(!context->parseRequest(buf,receiveTime))
    {
        conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
        conn->shutdown();
    }
    if (context->gotAll())//state_==gotALL
    {
    //请求已经解析完毕
        onRequest(conn, context->request());

        context->reset();//context reset
    }

}

#if 1
void HttpServer::onRequest(const muduo::net::TcpConnectionPtr& conn, const HttpRequest& req)
{
#if 1
    const string& connection = req.getHeader("Connection");
    bool close = connection == "close" ||
    (req.getVersion() == HttpRequest::HTTP10 && connection != "Keep-Alive");
    HttpResponse response(close);//构造响应
    httpCallback_(req, &response);//用户回调
    muduo::net::Buffer buf;
    //此时response已经构造好,将向客户发送Response添加到buffer中
    response.appendToBuffer(&buf);
    conn->send(&buf);
    //如果非Keep-Alive则直接关掉
    if (response.closeConnection())
    {
        conn->shutdown();
    }
#endif
}
#endif

按照TcpServer接收连接->处理连接这个顺序来看,首先将调用onConnection,该函数为Tcp连接创建Http上下文变量HttpContext,这个类主要用于接收客户请求(这里为Http请求),并解析请求。


(二)HttpContext

//HttpContext.h

#ifndef __HTTPCONTEXT_H__
#define __HTTPCONTEXT_H__

#include <muduo/base/copyable.h>
#include <muduo/net/Buffer.h>
#include "HttpRequest.h"
class Buffer;
class HttpContext:public muduo::copyable
{
    public:
    //解析请求的状态
    enum HttpRequestParseState
    {
        kExpectRequestLine,
        kExpectHeaders,
        kExpectBody,
        kGotAll,
    };

    HttpContext()
        : state_(kExpectRequestLine)
    {
    }

    bool parseRequest(muduo::net::Buffer* buf, muduo::Timestamp receiveTime)
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值