0%

分析基于epoll的C++高性能webServer代码(二)

分析基于epoll的C++高性能webServer代码(二)

C++bind()函数用法

  • 参考链接

  • std::bind()函数作为函数的适配器,它可以扩大函数是使用场合,使得函数更加灵活的被使用。
    template<class F, class… Args>

bind(F&&f, Args&&… args);
  • 参数:
    f 可以是function object,函数指针,函数引用,成员函数指针,或者数据成员的指针。
  • 返回值:
    function object

可以用std::placeholders::_1等替换函数本身的输入参数

  • 举例:
#include <iostream>
#include <functional>
using namespace std;

using namespace std::placeholders;

void func(int a, int b, int c)
{
cout << (a -b -c) << endl;
}

int main(int argc, char *argv[])
{
auto fn1 = bind(func, _1, 2, 3);
auto fn2 = bind(func, 2, _1, 3);

fn1(10);
fn2(10);
return 0;
}

/*
输出
5
-11
*/
  • 注意上面的三输入函数func使用bind替换掉了其中的两个输入参数,仅仅在placeholder的位置提供一个输入
  • 注意,当具有多个输入的时候,输入的顺序是按照std::placeholders::_1std::placeholders::_2std::placeholders::_3等的顺序
  • 举例:
#include <iostream>
#include <functional>

using namespace std;
using namespace std::placeholders;

void func(int a, int b, int c)
{
cout << (a - b -c) << endl;
}

int main(int argc, char *argv[])
{
auto fn1= bind(func, _2, 2, _1);
cout << "the value of function is :";
fn1(1, 13);

auto fn2 = bind(func, _1, 2, _2);
cout << "the value of function after changing placeholder position is :";
fn2(1, 13);
return 0;
}

/*
输出
the value of function is :10
the value of function after changing placeholder position is :-14
*/
  • 注意上面的函数中,fn1的实际输入到func中的参数是func(13, 2, 1),而输入到fn2中的参数实际上是func(1, 2, 13)

httpServer的成员函数分析

构造函数

  • 使用初始化列表初始化成员tcpserver_,然后将tcpserver_的函数接口全部初始化为HttpServer提供的处理函数
HttpServer::HttpServer(EventLoop *loop, int port)
: tcpserver_(loop, port),
cnt(0)
{
tcpserver_.SetNewConnCallback(std::bind(&HttpServer::HandleNewConnection, this, std::placeholders::_1));
tcpserver_.SetMessageCallback(std::bind(&HttpServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
tcpserver_.SetSendCompleteCallback(std::bind(&HttpServer::HandleSendComplete, this, std::placeholders::_1));
tcpserver_.SetCloseCallback(std::bind(&HttpServer::HandleClose, this, std::placeholders::_1));
tcpserver_.SetErrorCallback(std::bind(&HttpServer::HandleError, this, std::placeholders::_1));
}

HandleNewConnection(TcpConnection *ptcpconn)

  • 处理新建立的http连接请求
  • 新建一个HttpSession对象
  • 将该对象放入httpsessionlist_中(httpsessionlist_是一个map,通过TcpConnection映射到httpSession对象)
void HttpServer::HandleNewConnection(TcpConnection *ptcpconn)
{
//std::string msg(s);
HttpSession *phttpsession = new HttpSession();
httpsessionnlist_[ptcpconn] = phttpsession;
}

HandleMessage(TcpConnection *ptcpconn, std::string &s)

  • 调用httpsessionlist_中的对象处理信息
  • 将同样的数据发送回发送方(回显)
  • 处理短链接问题
void HttpServer::HandleMessage(TcpConnection *ptcpconn, std::string &s)
{
//std::cout << "http num is:" << ++cnt << std::endl;
HttpSession *phttpsession = httpsessionnlist_[ptcpconn];
phttpsession->PraseHttpRequest(s);
phttpsession->HttpProcess();
std::string msg;
phttpsession->AddToBuf(msg);
ptcpconn->Send(msg);
if(!phttpsession->KeepAlive())
{
//短连接,可以告诉框架层数据发完就可以关掉TCP连接,不过这里注释掉,还是交给客户端主动关闭吧
//ptcpconn->HandleClose();
}
}
  • HttpProcess()的行为:
void HttpSession::HttpProcess()
{
if("GET" == httprequestcontext_.method)
{
;
}
else if("POST" == httprequestcontext_.method)
{
;
}
else
{
std::cout << "HttpServer::HttpParser" << std::endl;
errormsg = "Method Not Implemented";
HttpError(501, "Method Not Implemented");
}

size_t pos = httprequestcontext_.url.find("?");
if(pos != std::string::npos)
{
path_ = httprequestcontext_.url.substr(0, pos);
querystring_ = httprequestcontext_.url.substr(pos+1);
}
else
{
path_ = httprequestcontext_.url;
}

//keepalive判断处理
std::map<std::string, std::string>::const_iterator iter = httprequestcontext_.header.find("Connection");
if(iter != httprequestcontext_.header.end())
{
keepalive_ = (iter->second == "Keep-Alive");
}
else
{
if(httprequestcontext_.version == "HTTP/1.1")
{
keepalive_ = true;//HTTP/1.1默认长连接
}
else
{
keepalive_ = false;//HTTP/1.0默认短连接
}
}

responsebody_.clear();
if("/" == path_)
{
path_ = "/index.html";
}
else if("/hello" == path_)
{
//Wenbbench 测试用
std::string filetype("text/html");
responsebody_ = ("hello world");
responsecontext_ += httprequestcontext_.version + " 200 OK\r\n";
responsecontext_ += "Server: Chen Shuaihao's NetServer/0.1\r\n";
responsecontext_ += "Content-Type: " + filetype + "; charset=utf-8\r\n";
if(iter != httprequestcontext_.header.end())
{
responsecontext_ += "Connection: " + iter->second + "\r\n";
}
responsecontext_ += "Content-Length: " + std::to_string(responsebody_.size()) + "\r\n";
responsecontext_ += "\r\n";
responsecontext_ += responsebody_;
return;
}
else
{
;
}

//std::string responsebody;
path_.insert(0,".");
FILE* fp = NULL;
if((fp = fopen(path_.c_str(), "rb")) == NULL)
{
//perror("error fopen");
//404 NOT FOUND
HttpError(404, "Not Found");
return;
}
else
{
char buffer[4096];
memset(buffer, 0, sizeof(buffer));
while(fread(buffer, sizeof(buffer), 1, fp) == 1)
{
responsebody_.append(buffer);
memset(buffer, 0, sizeof(buffer));
}
if(feof(fp))
{
responsebody_.append(buffer);
}
else
{
std::cout << "error fread" << std::endl;
}
fclose(fp);
}

std::string filetype("text/html"); //暂时固定为html
responsecontext_ += httprequestcontext_.version + " 200 OK\r\n";
responsecontext_ += "Server: Chen Shuaihao's NetServer/0.1\r\n";
responsecontext_ += "Content-Type: " + filetype + "; charset=utf-8\r\n";
if(iter != httprequestcontext_.header.end())
{
responsecontext_ += "Connection: " + iter->second + "\r\n";
}
responsecontext_ += "Content-Length: " + std::to_string(responsebody_.size()) + "\r\n";
responsecontext_ += "\r\n";
responsecontext_ += responsebody_;
}

HttpServer::HandleClose(TcpConnection *ptcpconn)

  • 通过传入的参数TcpConnecton和map映射找到对应的httpSession
  • httpSession从列表中删除
  • 释放httpSession占用的内存空间
void HttpServer::HandleClose(TcpConnection *ptcpconn)
{
HttpSession *phttpsession = httpsessionnlist_[ptcpconn];
httpsessionnlist_.erase(ptcpconn);
delete phttpsession;
}

HttpServer::HandleError(TcpConnection *ptcpconn)

  • 删除对应的httpSession同上
void HttpServer::HandleError(TcpConnection *ptcpconn)
{
HttpSession *phttpsession = httpsessionnlist_[ptcpconn];
httpsessionnlist_.erase(ptcpconn);
delete phttpsession;
}

HttpServer::Start()

  • 直接调用内部的tcpserver成员的start函数
void HttpServer::Start()
{
tcpserver_.Start();
}