brynet源码阅读——http组件和wrapper组件
0、引言
在前面的文章中介绍了brynet网络库中的各个组件,在这篇文章中介绍wrapper组件和http组件。其中wrapper组件是给用户使用使用的封装接口,用户只需要简单设置一些参数就可以搭建一个网络服务器或者客户端。而http组件是brynet中http部分的关键部分,依赖于开源的http_parser.h模块。
1、wrapper组件
1.1、ConnectionBuilder.hpp
该文件中封装了建立会话连接的Builder器,提供了一些简单的接口,用来给用户设置一些配置,设置完了配置可以直接调用asyncConnect启动连接。示例代码如下:
wrapper::ConnectionBuilder connectionBuilder;
connectionBuilder
.WithService(service)
.WithConnector(connector)
.WithMaxRecvBufferSize(1024 * 1024)
.AddEnterCallback(enterCallback);
1.2、HttpConnectionBuilder.hpp
这个类在ConnectionBuilder的基础上封装了一个专门用做Http会话连接的Builder类,看懂了ConnectionBuilder.hpp中的实现,这个文件中的类就是又封装了一层,比较简单。使用方法如下:
wrapper::HttpConnectionBuilder()
.WithConnector(connector)
.WithService(service)
.WithAddr("14.215.177.39", 80)
.WithTimeout(std::chrono::seconds(10))
.WithFailedCallback([]() {
std::cout << "connect failed" << std::endl;
})
.WithMaxRecvBufferSize(1000)
.WithEnterCallback([requestStr](const HttpSession::Ptr& session, HttpSessionHandlers& handlers) {
(void) session;
std::cout << "connect success" << std::endl;
session->send(requestStr);
handlers.setHttpBodyCallback([](const HTTPParser& httpParser,
const HttpSession::Ptr& session,
const char* body,
size_t length) {
(void) httpParser;
(void) session;
(void) body;
(void) length;
});
handlers.setHeaderCallback([](const HTTPParser& httpParser,
const HttpSession::Ptr& session) {
(void) httpParser;
(void) session;
});
handlers.setHttpEndCallback([](const HTTPParser& httpParser,
const HttpSession::Ptr& session) {
(void) session;
// because has call setHttpBodyCallback, so the body from http parser is empty.
std::cout << httpParser.getBody() << std::endl;
counter.fetch_add(1);
std::cout << "counter:" << counter.load() << std::endl;
session->postClose();
});
})
.asyncConnect();
1.3、HttpServiceBuilder.hpp
在ListenerBuilder的基础上封装了一层专门建立HttpService的Build器,只要理解了ListenerBuilder的原理,这里的代码非常简单。使用方法如下:
wrapper::HttpListenerBuilder listenBuilder;
listenBuilder
.WithService(service)
.AddSocketProcess([](TcpSocket& socket) {
socket.setNodelay();
})
.WithMaxRecvBufferSize(1024)
.WithAddr(false, "0.0.0.0", port)
.WithReusePort()
.WithEnterCallback([httpEnterCallback, wsEnterCallback](const HttpSession::Ptr& httpSession, HttpSessionHandlers& handlers) {
handlers.setHttpEndCallback(httpEnterCallback);
handlers.setWSCallback(wsEnterCallback);
})
.asyncRun();
1.4、ServiceBuilder.hpp
该文件中定义了建立服务的Builder类,监听线程和工作线程可以是1:1,也可以是1:n,这取决于mTcpService指向对象的类型,关键的成员函数理解如下:
// 服务器中真正的worker service,这里面都是监听的通信socket
ITcpService::Ptr mTcpService;
// 会话建立成功需要执行的callback
std::vector<ListenThread::TcpSocketProcessCallback> mSocketProcessCallbacks;
// 建立会话的参数
ConnectionOption mSocketOption;
// 监听的ip地址
std::string mListenAddr;
// 监听的端口
int mPort = 0;
bool mIsIpV6 = false;
bool mEnabledReusePort = false;
// 监听线程
ListenThread::Ptr mListenThread;
2、http组件
2.1、http_parser.h
这部分是开源的库,用来解析Http的请求命令和响应命令,这部分代码还没有仔细研究,使用方法和其他的库类似,都是通过一些callback将解析到的数据保存到自己定义的数据结构中。
2.2、HttpFormat.hpp
该文件中定义了两个关键类,一个是HttpRequest、一个是HttpResponse。其中HttpRequest是Http请求的结构体,在发送请求之前,创建一个对象,并通过提供的接口设置参数,最后通过getResult() 接口获得Http请求指令的字符串,这样就可以通过通信套接字发送出去。同理,HttpResponse是响应的Http指令。网络库中定义这两个类是常见做法。
2.3、HttpParser.hpp
该文件中定义了HTTPParser类,http解析类,借助开源的http_parser.h,核心思想是将接收到的字符串利用http_parser.h将其解析并将解析出来的内容利用callback的形式放到类的成员变量中,并且会执行对应的callback函数。brynet在制作返回的HttpResponse时是在callback函数中做的,并不像sylar框架那样,callback中只将命令分解出来,真正的做请求响应动作是在serverlet中做的。下面介绍下各个成员变量的含义:
// http_parser中的数据结构
const http_parser_type mParserType;
http_parser mParser;
// 解析的时候用到的callback
http_parser_settings mSettings;
// 方法
int mMethod = -1;
bool mIsUpgrade = false;
bool mIsWebSocket = false;
// 链接是否alive
bool mIsKeepAlive;
// 解析是否结束
bool mISCompleted;
// 下面这些成员变量主要用于存储解析出来的数据
std::string mPath;
std::string mQuery;
std::string mStatus;
std::map<std::string, std::string> mHeadValues;
int mStatusCode;
// 存放解析出来的url、body
std::string mUrl;
std::string mBody;
// websocket相关的
std::string mWSCacheFrame;
std::string mWSParsePayload;
WebSocketFormat::WebSocketFrameType mWSFrameType;
// 解析完头需要执行的callback
std::function<void()> mHeaderCallback;
// 解析完body需要执行的callback
std::function<void(const char*, size_t)> mBodyCallback;
// 解析完成需要执行的callback,可以将HttpResponse的拼装放到这里面做
std::function<void()> mMsgEndCallback;
2.4、HttpService.hpp
该文件中定义了3个类,Http会话类HttpSession、Http会话类相关的callback函数和HttpService类。HttpService类中的关键函数代码如下
static void setup(const TcpConnection::Ptr& session,
const HttpSession::EnterCallback& enterCallback)
{
if (enterCallback == nullptr)
{
throw BrynetCommonException("not setting http enter callback");
}
auto httpParser = std::make_shared<HTTPParser>(HTTP_BOTH);
auto httpSession = HttpSession::Create(session);
HttpSessionHandlers handlers;
// 这里一般会往handlers中设置一些回调函数,等到解析器解析到对应的数据后,才会执行对应的callback函数
enterCallback(httpSession, handlers);
httpSession->setClosedCallback(std::move(handlers.mCloseCallback));
httpSession->setWSCallback(std::move(handlers.mWSCallback));
httpSession->setWSConnected(std::move(handlers.mWSConnectedCallback));
// 设置callback到httpParser
auto headerCB = handlers.mHttpHeaderCallback;
if (headerCB != nullptr)
{
httpParser->setHeaderCallback([=]() {
headerCB(*httpParser, httpSession);
});
}
auto bodyCB = handlers.mHttpBodyCallback;
if (bodyCB != nullptr)
{
httpParser->setBodyCallback([=](const char* body, size_t length) {
bodyCB(*httpParser, httpSession, body, length);
});
}
// 一般在这里的callback会组装HttpResponse
auto endCB = handlers.mHttpEndCallback;
if (endCB != nullptr)
{
httpParser->setEndCallback([=]() {
endCB(*httpParser, httpSession);
});
}
// 这里也是设置callback函数
HttpService::handle(httpSession, httpParser);
}