epoll的簡單實現

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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章