saDGFH 2021-09-20 17:25 采纳率: 0%
浏览 9
已结题

web服务器中epoll无限阻塞不返回.

按游双的高性能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);
};

  • 写回答

1条回答 默认 最新

  • 有问必答小助手 2021-09-22 10:13
    关注

    你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,技术专家团超时未为您做出解答


    本次提问扣除的有问必答次数,将会以问答VIP体验卡(1次有问必答机会、商城购买实体图书享受95折优惠)的形式为您补发到账户。


    因为有问必答VIP体验卡有效期仅有1天,您在需要使用的时候【私信】联系我,我会为您补发。

    评论

报告相同问题?

问题事件

  • 系统已结题 9月28日
  • 创建了问题 9月20日

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器