欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

epoll的简单实现

程序员文章站 2024-03-23 10:57:58
...

1.Network.h

#ifndef NETWORK_H
#define NETWORK_H
#include <iostream>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <map>
#define  MAX_COUNT          1000               //最大连接数
using namespace std;

enum IOOperType {
    TYPE_ACP,            //accept事件到达,有新连接请求
    TYPE_RECV,           //数据接收事件
};


struct DataPackage
{
    //接收缓存区
    char                      RecvBuffer[1024];
    //发送缓存区
    char                      SendBuffer[1024];
    //对端信息
    struct sockaddr           addr;
    //对端信息长度
    socklen_t                 length;
    //
    int                       socket;

    int                       EventType;
    DataPackage()
    {
        memset(RecvBuffer,0,sizeof(RecvBuffer));
        memset(SendBuffer,0,sizeof(SendBuffer));
        length=sizeof(sockaddr);
    }
    void ResetRecvBuffer()
    {
        memset(RecvBuffer,0,sizeof(RecvBuffer));
    }
    void ResetSendBuffer()
    {
        memset(SendBuffer,0,sizeof(SendBuffer));
    }
};
struct EpollEvent:public epoll_event
{
    EpollEvent(){}

    EpollEvent(DataPackage* pData)
    {
        data.ptr=(void*)pData;
    }
    ~EpollEvent()
    {

    }
    DataPackage* GetDataPackage()
    {
        return (DataPackage*)data.ptr;
    }
    void DeleteDataPackage()
    {
         delete (DataPackage*)data.ptr;
    }
};


class Network
{
private:
    int                         m_iListenSocket;                        //监听socket
    int                         m_iEpollCreateFd;                       //epoll的句柄
    EpollEvent                  m_sWait_event[MAX_COUNT];               //接收事件
    map<int,DataPackage*>       m_ConnectList;                          //用户连接列表
public:
    Network();
    virtual ~Network();
    //开始监听
    bool StartListen(unsigned short port, char*ip);
    //投递Accep
    bool DeliveryAccept();
    //投递Recv
    bool DeliveryRecv(DataPackage* pack);
    //断开连接
    bool Disconnect(EpollEvent* Wait_event);
protected:

private:
    //等待事件
    bool    WaitForTheEvent();
    //设置文件描述符为NonBlock
    bool    setNonBlock(int fd);
    //处理连接消息
    bool    HandleAccept();
    //处理接收消息
    bool    HandRecv(int i);
};

#endif // NETWORK_H

2.Network.cpp

#include "../include/Network.h"
#include<fcntl.h>
#include<unistd.h>
Network::Network()
{

}

Network::~Network()
{
    map<int,DataPackage*> ::iterator it=m_ConnectList.begin();
    for(;it!=m_ConnectList.end();)
    {
        if(it->second!=NULL)
           {
               it=m_ConnectList.erase(it);
               delete it->second;
           }
        else
           it++;
    }
}
bool Network::StartListen(unsigned short port, char* ip)
{
    //创建一个监听socket
    m_iListenSocket=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in server_addr;
    server_addr.sin_family=AF_INET;
    inet_pton(AF_INET,ip,&(server_addr.sin_addr));
   // server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port=htons(port);
    int opt=1;
    setsockopt(m_iListenSocket, SOL_SOCKET,SO_REUSEADDR, (const void *) &opt, sizeof(opt));
    //将socket与ip端口绑定
    bind(m_iListenSocket,(struct sockaddr*)&server_addr,sizeof(server_addr));
    //创建一个套接口并监听连接
    listen(m_iListenSocket,100);
    //创建一个epoll句柄
    m_iEpollCreateFd=epoll_create(10);
    if(-1==m_iEpollCreateFd)
    {
        perror("创建文件描述符失败");
        return false;
    }
    //投递accept
    if(!DeliveryAccept())
        return false;

    WaitForTheEvent();
    return true;
}
//设置文件描述符为非阻塞
bool Network::setNonBlock(int fd)
{
   int flags = fcntl(fd, F_GETFL, 0);
   flags |= O_NONBLOCK;
   if(-1 == fcntl(fd, F_SETFL, flags))
   {
       return false;
   }
    return true;
}
bool Network::WaitForTheEvent()
{
    while(true)
    {
        //等待事件通知
       int clRet=epoll_wait(m_iEpollCreateFd,m_sWait_event,1,-1);
       for(int i=0;i<clRet;i++)
       {
           DataPackage* pack=m_sWait_event[i].GetDataPackage();
           switch(pack->EventType)
           {
           case  TYPE_ACP:
                {
                    HandleAccept();
                    break;
                }
           case TYPE_RECV:
                {
                    HandRecv(i);
                    break;
                }
           default:
                {
                   printf("m_sWait_event error\n");
                   break;
                }
           }
       }
    }
}
//投递Accep
bool Network::DeliveryAccept()
{
    //将socket绑定一个事件
    DataPackage* pack=new DataPackage;
    EpollEvent AcceptEvent(pack);
    pack->socket=m_iListenSocket;
    pack->EventType=TYPE_ACP;
    //设置为可读并且是边缘触发
    AcceptEvent.events=EPOLLIN|EPOLLET;
    //注册一个监听事件
    int clRet=epoll_ctl(m_iEpollCreateFd,EPOLL_CTL_ADD,pack->socket,&AcceptEvent);
    if(-1==clRet)
    {
        perror("注册监听事件类型失败");
        return false;
        AcceptEvent.DeleteDataPackage();
    }
    return true;
}
//投递Recv
bool Network::DeliveryRecv(DataPackage* pack)
{
    EpollEvent pData(pack);
    pData.events=EPOLLIN|EPOLLET;
    pack->EventType=TYPE_RECV;
    //注册一个事件
    int clRet=epoll_ctl(m_iEpollCreateFd,EPOLL_CTL_ADD,pack->socket,&pData);

    if( pack->socket<=0||-1==clRet||!setNonBlock( pack->socket))
    {
        perror("accept error:");
        close(pack->socket);
        pData.DeleteDataPackage();
        return false;
    }
    return true;
}
bool Network::Disconnect(EpollEvent* Wait_event)
{
    DataPackage * pack=Wait_event->GetDataPackage();
    int clRet=epoll_ctl(m_iEpollCreateFd,EPOLL_CTL_DEL,pack->socket,Wait_event);
    if(-1==clRet)
    {
         perror("Disconnect error:");
         return false;
    }
    printf("客户端下线\n");
    close(pack->socket);

    map<int,DataPackage*> ::iterator it=m_ConnectList.find(pack->socket);
    if(it!=m_ConnectList.end())
       m_ConnectList.erase(it);

    Wait_event->DeleteDataPackage();
    return true;
}
bool Network::HandleAccept()
{
    DataPackage* pack=new DataPackage;
    pack->socket=accept(m_iListenSocket,&pack->addr,&pack->length);
    //投递一个recv
    if(DeliveryRecv(pack))
    {
      //存入连接列表
      m_ConnectList.insert(make_pair(pack->socket,pack));
      return true;
    }

    return false;
}
bool Network::HandRecv(int i)
{
    DataPackage * pack=m_sWait_event[i].GetDataPackage();
    pack->ResetRecvBuffer();
    int len=recv(pack->socket,pack->RecvBuffer,sizeof(pack->RecvBuffer),0);
    if(len<=0)
    {
       return Disconnect(&m_sWait_event[i]);
    }
    else
    {
        printf("data:%s\n",pack->RecvBuffer);
    }
    return true;
}