按游双的高性能web服务器写了一个用智能指针代替裸指针c++版,一直都跑的好好的,今天开机加上定时器之后就抽风了
epoll无限阻塞.
我简单调试了一下,发现不用构造函数实例化对象就能正常使用了
构造函数大概是:void func(int x){ clientfd = x }//给用户实例初始化一个变量
这样的,如果x<5,就会出问题,x=4的时候(恰好等于epollfd)就会无限返回-1,等于3(恰好等于serverfd)时就会无限阻塞.
此外,当接受连接并初始化对象后,无法正常接受http报文了,不初始化对象就能正常使用.
这是为什么呢?
解答悬赏20,加我微信支付
以下源码
main:
int main()
{
//启动线程池
threadPool::initThreadPool(POOLSIZE);
//创建服务器socket连接
int hostfd = setHostSock(8877);
if (hostfd == -1)
{
printf("error1");
return -1;
}
//将socket设置为非阻塞
setNonBlocking(hostfd);
//初始化epoll
int epollfd = epoll::epollinit(hostfd, EPOLLMAX);
if (epollfd == -1)
{
printf("error2");
close(hostfd);
close(epollfd);
return -1;
}
client::initClient(hostfd, epollfd);
//oneloop
while(1)
{
epoll::epollwait(1000,-1);
}
cout << "ok" << endl;
return 0;
}
client.h:
using namespace::std;
class timer;
enum CHECK_STATE
{
CHECK_STATE_REQUESTLINE = 0, //此时正在分析请求行
CHECK_STATE_HEADER, //此时正在分析头部字段
CHECK_STATE_CONTENT //内容
};
enum LINE_STATUS
{
LINE_OK = 0, //读到了完整的行
LINE_BAD, //读取行错误
LINE_LOADING //读取的行不完整,还需要继续输入
};
enum HTTP_CODE
{
NO_REQUEST, //请求不完整,需要继续读入行
GET_REQUEST, //获得了完整的请求
BAD_REQUEST, //活的请求的语法错误
FILE_REQUEST, //文件已被请求
FORBIDDEN_REQUEST, //客户访问权限不足
INTERNAL_ERROR, //服务器出错
CLOSED_CONNECTION //客户端已经关闭了连接
};
enum METHOD
{
GET = 0, POST, HEAD, PUT, DELETE, TRACE, OPTIONS, CONNCT, PATCH
};
class client
{
public:
client()
{
}
client(int fd)
{
clientfd = fd;
}
client(int fd , struct sockaddr_in caddr)
{
clientAddr = caddr;
clientfd = fd;
}
~client()
{
closeConnect();
}
//typedef std::shared_ptr<client> sharedptr_client;
static int epollfd;
static int hostfd;
std::weak_ptr<timer> clientTimer;
int clientfd; //对应sockfd
struct sockaddr_in clientAddr;
string readbuff;
string writebuff;
CHECK_STATE checkState = CHECK_STATE_REQUESTLINE;
METHOD method = GET;
string urlstr;
string version;
map<string, string> header;
bool isKeepAlive = false;
string path;
//int read_idx = 0;
bool forWrite = false;
bool forRead = false;
public:
int closeConnect();
bool write();
bool read();
int process();
bool isforRead();
bool isforWrite();
void setRead();
void setWrite();
HTTP_CODE process_read();
bool process_write(HTTP_CODE flag);
HTTP_CODE request_line_parse(); //请求行解析
HTTP_CODE headers_parse(); //头部解析
HTTP_CODE requestResponse(); //对获得的请求进行反馈
void add_status_line(int code, string buff); //写入状态行
void add_header(int code); //首部字段
void add_content(string buff); //内容
void add_content_len(int content_len);
void add_connection();
void add_blank();
bool stringcmp(string s1,string s2);
int get_space(string s,int begin,int end);
int get_url(int endflag);
int linktimer(shared_ptr<timer>t);
static int acceptNewConnect(int hostfd);
static void initClient(int hostfd_, int epollfd_);
static int clientDistribute(int eventnum , epoll_event* events_);
};
#include "client.h"
int client::hostfd;
int client::epollfd;
std::shared_ptr<client>* epoll::clients;
timerManager epoll::timer_manager;
string ok_200_title("OK");
string root_doc("/home/whd/webserver");
string test("<html><body>hello<body><html>");
enum process_mode
{
READMODE = 0,
WRITEMODE = 1
};
int client::closeConnect()
{
epoll::del_epoll(this->clientfd);
return 0;
}
bool client::write()
{
send(clientfd, writebuff.c_str(), writebuff.size(), 0);
return false;
}
bool client::read()
{
char* recvbuff = new char[2048];
while (1)
{
int re = recv(clientfd, recvbuff, 2048, 0);
if (re == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
break;
}
return false;
}
else if (re == 0)
{
return false;
}
readbuff.append(recvbuff,re);
memset(recvbuff, 0, 2048);
}
return true;
}
int client::process()
{
process_mode MODE;
if (isforRead())
MODE = READMODE;
else if (isforWrite())
MODE = WRITEMODE;
switch (MODE)
{
case READMODE: {
HTTP_CODE re_read = process_read();
if (re_read == NO_REQUEST)
{
epoll::mod_epoll(this->clientfd, EPOLLIN);
return 0;
}
process_write(re_read);
epoll::mod_epoll(clientfd, EPOLLOUT);
break;
}
case WRITEMODE: {
write();
break;
}
default:
break;
}
}
bool client::isforRead()
{
bool re = forRead;
if (forRead == true)
forRead = false;
return re;
}
bool client::isforWrite()
{
bool re = forWrite;
if (forWrite == true)
forWrite = false;
return re;
}
void client::setRead()
{
forRead = true;
}
void client::setWrite()
{
forWrite = true;
}
HTTP_CODE client::process_read()
{
bool readresult = read();
if (readresult == false)
{
//如果读入失败,就关闭socket,注销事件
this->closeConnect();
}
//获取一行的长度,如果小于0,说明读取不完整
HTTP_CODE re;
while (re!= GET_REQUEST)
{
switch (checkState)
{
case CHECK_STATE_REQUESTLINE: {
re = request_line_parse();
if (re == BAD_REQUEST)
{
return BAD_REQUEST;
}
break;
}
case CHECK_STATE_HEADER: {
re = headers_parse();
if (re == BAD_REQUEST)
{
return BAD_REQUEST;
}
else if (re == GET_REQUEST)
{
return requestResponse();
}
break;
}
default:
break;
}
}
}
HTTP_CODE client::request_line_parse()
{
int endflag = 0;
for (; endflag < readbuff.size(); endflag++)
{
if (endflag == readbuff.size() - 1)
return BAD_REQUEST;
if (readbuff[endflag] == '\r' && readbuff[endflag + 1] == '\n')
break;
}
endflag++;
string requestRow = readbuff.substr(0, endflag - 1);
if (stringcmp(requestRow, "GET"))
method = GET;
else {
return BAD_REQUEST;
}
int urled = get_url(endflag);
if(urled <0)
return BAD_REQUEST;
int ver = urled;
for (; ver <= endflag; ver++)
{
if (ver == endflag)
{
ver = -1;
break;
}
if (readbuff[ver + 1] == '\r')
break;
}
if (ver <= 0)
return BAD_REQUEST;
version = readbuff.substr(urled, ver + 1 - urled);
if (stringcmp(version, "HTTP/1.1") != true)
{
return BAD_REQUEST;
}
if (stringcmp(urlstr, "http://") == true)
{
urlstr = urlstr.substr(6);
}
if (urlstr.size() == 0 || urlstr[0] != '/')
return BAD_REQUEST;
checkState = CHECK_STATE_HEADER;
return NO_REQUEST;
}
HTTP_CODE client::headers_parse()
{
checkState = CHECK_STATE_HEADER;
return GET_REQUEST;
}
HTTP_CODE client::requestResponse()
{
return GET_REQUEST;
string realflie = root_doc + urlstr;
int resfd = open(realflie.c_str(), O_RDONLY);
return FILE_REQUEST;
}
void client::add_status_line(int code, string buff)
{
writebuff.append(version+" ");
writebuff.append( numtostr(code) + " ");
writebuff.append(buff + "\r\n");
}
void client::add_header(int code)
{
add_content_len(code);
add_connection();
add_blank();
}
void client::add_content(string buff)
{
writebuff.append(test);
}
void client::add_content_len(int content_len)
{
writebuff.append("Content_length: " + numtostr(content_len) + "\r\n");
}
void client::add_connection()
{
writebuff.append("Connection: ");
if (isKeepAlive == false)
writebuff.append("close");
else
writebuff.append("keep-alive");
writebuff.append("\r\n");
return;
}
void client::add_blank()
{
//timer t;
writebuff.append("\r\n");
}
bool client::process_write(HTTP_CODE flag)
{
switch (flag)
{
case NO_REQUEST:
break;
case GET_REQUEST:
{
add_status_line(200, ok_200_title);
add_header(test.size());
add_content(test);
break;
}
case BAD_REQUEST:
break;
case FILE_REQUEST:
break;
case FORBIDDEN_REQUEST:
break;
case INTERNAL_ERROR:
break;
case CLOSED_CONNECTION:
break;
default:
break;
}
}
bool client::stringcmp(string s1, string s2)
{
int l1 = s1.size(), l2 = s2.size();
for (int i = 0; i < l1; i++)
{
if (s1[i] >= 65 && s1[i] <= 90) s1[i] = tolower(s1[i]);
}
for (int i = 0; i < l2; i++)
{
if (s2[i] >= 65 && s2[i] <= 90) s2[i] = tolower(s2[i]);
}
int re = s1.find(s2);
if (re >= 0)
return true;
return false;
}
int client::get_space(string s,int begin,int end)
{
for (int i = begin; i <= end; i++)
{
if (i == end)
return -1;
if (s[i] == ' ')
return i;
}
return -1;
}
int client::get_url(int endflag)
{
int url = get_space(readbuff, 0, endflag);
url++;
if (url == 0)
return -1;
int urlend = get_space(readbuff, url, endflag);
urlend--;
if (urlend < 0)
return -1;
urlstr = readbuff.substr(url, urlend + 1 - url);
return urlend+2;
}
client s1;
int client::linktimer(shared_ptr<timer> t)
{
clientTimer = t;
return 0;
}
int client::acceptNewConnect(int hostfd)
{
struct sockaddr_in clientaddr;
socklen_t clientLen = sizeof(clientaddr);
int connfd = accept(epoll::hostFd, (sockaddr*)&clientaddr, &clientLen);
if (connfd <= 3)
{
printf("connfd accept error");
return -1;
}
setNonBlocking(connfd);
//printf("connfd conm from %s", inet_ntoa(clientaddr.sin_addr));
epoll::add_epoll(connfd);
//epoll::clients[connfd] = std::make_shared<client>(client(connfd,clientaddr));
//绑定定时器
epoll::timer_manager.addTimer(epoll::clients[connfd]);
//epoll::timer_manager.addTimer(epoll::clients[connfd]);
return 0;
}
void client::initClient(int hostfd_, int epollfd_)
{
client::hostfd = hostfd_;
client::epollfd = epollfd_;
epoll::clients = new shared_ptr<client>[1024];
//sizeof(shared_ptr<client>);
//make_shared<client>(client(hostfd));
//make_shared<client>(client(5));
//epoll::clients[hostfd] = make_shared<client>(client(hostfd));
return;
}
int client::clientDistribute(int eventnum, epoll_event* events_)
{
for (int i = 0; i < eventnum; i++)
{
int newfd = events_[i].data.fd;
if (newfd == epoll::hostFd)
{
//新链接
int re = acceptNewConnect(epoll::hostFd);
}
else if (events_[i].events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR))
{
//出现异常,断开连接
if(epoll::clients[newfd])
timerManager::delTimer(epoll::clients[newfd]->clientTimer);
epoll::clients[newfd].reset();
}
else if (events_[i].events&EPOLLIN )
{
epoll::clients[newfd]->setRead();
epoll::clients[newfd]->clientTimer.lock()->timeRefresh();
threadPool::taskAppend(epoll::clients[newfd]);
}
else if (events_[i].events & EPOLLOUT)
{//将writebuff发出即可
epoll::clients[newfd]->setWrite();
epoll::clients[newfd]->clientTimer.lock()->timeRefresh();
threadPool::taskAppend(epoll::clients[newfd]);
}
else {}
timerManager::clearDeads();
}
return 0;
}
using namespace::std;
class client;
class timer
{
public:
timer()
{
}
timer(shared_ptr<client> ptr) {
clientdata = ptr;
timeInit();
}
shared_ptr<client> clientdata;
size_t deadline;
static size_t timeout;
private:
bool isdead = false;
public:
bool isLate();
void timeRefresh();
void setDead();
void timeInit();
};
struct timeCmp
{
public:
bool operator() (shared_ptr<timer>& t1, shared_ptr<timer>& t2)const
{
return t1.get()->deadline > t2.get()->deadline;
}
};
class timerManager
{
private:
static MutexLock mutex_;
static priority_queue<shared_ptr<timer>, deque<shared_ptr<timer>>, timeCmp> timerQueue;
public:
static void clearDeads();
void addTimer(shared_ptr<client>& t1);
static void delTimer(weak_ptr<timer> spt);
};