HttpServer服务端测试模块-详解[5-1]
来源:互联网 发布:深圳市信诚网络 编辑:程序博客网 时间:2024/05/17 21:39
主流程如下:之前章节大体介绍了下各模块,这里我们主要看看我们的应用HttpServer类是如何使用muduo库的.
可以参考:
博客[4-2]可知,当上层初始化TcpServer之后:
由于初始化TcpServer里面,new Acceptor 这里面会建立socket 并绑定本地addr,epoll中关注该socket的读事件;由于这里给Acceptor 注册TcpServer::newConnection函数,因此当监听套接字发生读事件时候执行TcpServer::newConnection函数;
当上层接着调用TcpServer::start()该函数中调用Acceptor::listen 之后:
当新客户连接时候则调用TcpServer::newConnection 函数,该函数里面来一个客户端则new一个 TcpConnection 对象, 接着给该客户端注册回调函数, 即TcpServer的上层给TcpServer设置的回调函数: connectionCallback; messageCallback_; writeCompleteCallback_;
那么这些回调函数在哪呢?
即 HttpServer初始化中
server_.setConnectionCallback(
boost::bind(&HttpServer::onConnection, this, _1));
server_.setMessageCallback(
boost::bind(&HttpServer::onMessage, this, _1, _2, _3));
HttpServer_test.cc
#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);
resp->setStatusMessage("OK");
resp->setContentType("text/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")
{
resp->setStatusCode(HttpResponse::k200Ok);
resp->setStatusMessage("OK");
resp->setContentType("image/png");
resp->setBody(string(favicon, sizeof favicon));
}
else if (req.path() == "/hello")
{
resp->setStatusCode(HttpResponse::k200Ok);
resp->setStatusMessage("OK");
resp->setContentType("text/plain");
resp->addHeader("Server", "Muduo");
resp->setBody("hello, world!\n");
}
else
{
resp->setStatusCode(HttpResponse::k404NotFound);
resp->setStatusMessage("Not Found");
resp->setCloseConnection(true);
}
}
int main(int argc, char* argv[])
{
int numThreads = 0;
if (argc > 1)
{
benchmark = true;
Logger::setLogLevel(Logger::WARN);
numThreads = atoi(argv[1]);
}
EventLoop loop;
HttpServerserver(&loop, InetAddress(8000), "dummy");
server.setHttpCallback(onRequest); //给HttpServerserver设置回调函数
server.setThreadNum(numThreads);
server.start();
loop.loop();
}
HttpServer.h
#ifndef MUDUO_NET_HTTP_HTTPSERVER_H
#define MUDUO_NET_HTTP_HTTPSERVER_H
#include <muduo/net/TcpServer.h>
#include <boost/noncopyable.hpp>
namespace muduo
{
namespace net
{
class HttpRequest;
class HttpResponse;
/// A simple embeddable HTTP server designed for report status of a program.
/// It is not a fully HTTP 1.1 compliant server, but provides minimum features
/// that can communicate with HttpClient and Web browser.
/// It is synchronous, just like Java Servlet.
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)
{
httpCallback_ = cb;
}
void setThreadNum(int numThreads)
{
server_.setThreadNum(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_;
HttpCallback httpCallback_;
};
}
}
#endif // MUDUO_NET_HTTP_HTTPSERVER_H
HttpServer.cc
#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>
#include <boost/bind.hpp>
using namespace muduo;
using namespace muduo::net;
namespace muduo
{
namespace net
{
namespace detail
{
// FIXME: move to HttpContext class
bool processRequestLine(const char* begin, const char* end, HttpContext*context)
{
bool succeed = false;
const char* start = begin;
const char* space = std::find(start, end, ' ');
HttpRequest& request = context->request();
if (space != end && request.setMethod(start, space))
{
start = space+1;
space = std::find(start, end, ' ');
if (space != end)
{
request.setPath(start, space);
start = space+1;
succeed = end-start == 8 && std::equal(start,end-1, "HTTP/1.");
if (succeed)
{
if (*(end-1) == '1')
{
request.setVersion(HttpRequest::kHttp11);
}
else if (*(end-1) == '0')
{
request.setVersion(HttpRequest::kHttp10);
}
else
{
succeed = false;
}
}
}
}
return succeed;
}
// FIXME: move to HttpContext class
// return false if any error
bool parseRequest(Buffer* buf, HttpContext* context, Timestamp receiveTime)
{
bool ok = true;
bool hasMore = true;
while (hasMore)
{
if (context->expectRequestLine())
{
const char* crlf = buf->findCRLF();
if (crlf)
{
ok = processRequestLine(buf->peek(), crlf,context);
if (ok)
{
context->request().setReceiveTime(receiveTime);
buf->retrieveUntil(crlf + 2);
context->receiveRequestLine();
}
else
{
hasMore = false;
}
}
else
{
hasMore = false;
}
}
else if (context->expectHeaders())
{
const char* crlf = buf->findCRLF();
if (crlf)
{
const char* colon = std::find(buf->peek(), crlf,':');
if (colon != crlf)
{
context->request().addHeader(buf->peek(),colon, crlf);
}
else
{
// empty line, end of header
context->receiveHeaders();
hasMore = !context->gotAll();
}
buf->retrieveUntil(crlf + 2);
}
else
{
hasMore = false;
}
}
else if (context->expectBody())
{
// FIXME:
}
}
return ok;
}
void defaultHttpCallback(const HttpRequest&, HttpResponse* resp)
{
resp->setStatusCode(HttpResponse::k404NotFound);
resp->setStatusMessage("Not Found");
resp->setCloseConnection(true);
}
}
}
}
/*
初始化TcpServer, 并给TcpServer 的connectionCallback_注册函数HttpServer::onConnection
给TcpServer 的messageCallback_注册函数HttpServer::onMessage
*/
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));
}
HttpServer::~HttpServer()
{
}
/*
执行TcpServer.start();
*/
void HttpServer::start()
{
LOG_WARN << "HttpServer[" << server_.name()
<< "] starts listenning on " <<server_.hostport();
server_.start();
}
void HttpServer::onConnection(const TcpConnectionPtr& conn)
{
if (conn->connected())
{
conn->setContext(HttpContext());//当客户端已经连接上时给客户端TcpConnectionPtr设置拥有成员为HttpContext()
}
}
/*当客户端发来数据时候下层会调用该函数,buf中存放的是客户端的消息,解析消息将其有用内容存于客户端TcpConnectionPtr成员context 中, 接着调用onRequest响应客户端*/
void HttpServer::onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
HttpContext* context = boost::any_cast<HttpContext>(conn->getMutableContext());
if (!detail::parseRequest(buf, context, receiveTime))
{
conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
conn->shutdown();
}
if (context->gotAll())
{
onRequest(conn, context->request());
context->reset();
}
}
/*
即调用HttpServer_test.cc文件中main函数中 server.setHttpCallback(onRequest);注册的onRequest函数去处理
*/
void HttpServer::onRequest(const TcpConnectionPtr& conn, constHttpRequest& req)
{
const string& connection = req.getHeader("Connection");
bool close = connection == "close" ||
(req.getVersion() == HttpRequest::kHttp10 && connection!= "Keep-Alive");
HttpResponse response(close);
httpCallback_(req, &response);
Buffer buf;
response.appendToBuffer(&buf);
conn->send(&buf);
if (response.closeConnection())
{
conn->shutdown();
}
}
HttpContext.h
#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H
#define MUDUO_NET_HTTP_HTTPCONTEXT_H
#include <muduo/base/copyable.h>
#include <muduo/net/http/HttpRequest.h>
namespace muduo
{
namespace net
{
class HttpContext : public muduo::copyable
{
public:
enum HttpRequestParseState
{
kExpectRequestLine,
kExpectHeaders,
kExpectBody,
kGotAll,
};
HttpContext()
: state_(kExpectRequestLine)
{
}
// default copy-ctor, dtor and assignment are fine
bool expectRequestLine() const
{ return state_ == kExpectRequestLine; }
bool expectHeaders() const
{ return state_ == kExpectHeaders; }
bool expectBody() const
{ return state_ == kExpectBody; }
bool gotAll() const
{ return state_ == kGotAll; }
void receiveRequestLine()
{ state_ = kExpectHeaders; }
void receiveHeaders()
{ state_ = kGotAll; } // FIXME
void reset()
{
state_ = kExpectRequestLine;
HttpRequest dummy;
request_.swap(dummy);
}
const HttpRequest& request() const
{ return request_; }
HttpRequest& request()
{ return request_; }
private:
HttpRequestParseState state_;
HttpRequest request_;
};
}
}
#endif // MUDUO_NET_HTTP_HTTPCONTEXT_H
- HttpServer服务端测试模块-详解[5-1]
- Tornado httpserver模块
- JDK6中httpserver创建http服务端实例
- HttpServer
- httpserver
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Spring MVC测试框架详解——服务端测试
- Node中http模块详解(服务端篇)
- Node中http模块详解(服务端篇)
- Node中http模块详解(服务端篇)
- 谁来帮帮我!公司强硬留人!
- Linux下X86与MIPS区别之一:代码放在数据区是否可以被执行
- 海量日志数据__怎么在海量数据中找出重复次数最多的一个;提取出某日访问网站次数最多的那个IP;提取出某日访问网站次数最多的前n个IP
- C#中异步SOCKET发送数据时内存问题
- Android adb常用指令使用指南
- HttpServer服务端测试模块-详解[5-1]
- 2014CVPR
- 修改oraclexe的默认http端口
- 从预防缓冲区溢出看MIPS与X86在函数调用开辟栈的区别
- hibernate之级联cascade和关系维持inverse
- java web 过滤器
- 64位系统的Detours
- java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,
- 黑马程序员笔记——Java面向对象之static关键字和单例设计模式