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