Epoller反应器封装
实现思路:
- 容器:std::vector events_;
- 操作:对epoll创建,关闭,添加,修改,删除,等待进行封装
头文件
#ifndef EPOLLER_H
#define EPOLLER_H
#include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <vector>
#include <errno.h>
class Epoller {
public:
explicit Epoller(int maxEvent = 1024);
~Epoller();
bool AddFd(int fd, uint32_t events);
bool ModFd(int fd, uint32_t events);
bool DelFd(int fd);
int Wait(int timeoutMs = -1);
int GetEventFd(size_t i) const;
uint32_t GetEvents(size_t i) const;
private:
int epollFd_;
std::vector<struct epoll_event> events_;
};
#endif
#endif
源文件
#include "epoller.h"
Epoller::Epoller(int maxEvent):epollFd_(epoll_create(512)), events_(maxEvent){
assert(epollFd_ >= 0 && events_.size() > 0);
}
Epoller::~Epoller() {
close(epollFd_);
}
bool Epoller::AddFd(int fd, uint32_t events) {
if(fd < 0) return false;
epoll_event ev = {0};
ev.data.fd = fd;
ev.events = events;
return 0 == epoll_ctl(epollFd_, EPOLL_CTL_ADD, fd, &ev);
}
bool Epoller::ModFd(int fd, uint32_t events) {
if(fd < 0) return false;
epoll_event ev = {0};
ev.data.fd = fd;
ev.events = events;
return 0 == epoll_ctl(epollFd_, EPOLL_CTL_MOD, fd, &ev);
}
bool Epoller::DelFd(int fd) {
if(fd < 0) return false;
epoll_event ev = {0};
return 0 == epoll_ctl(epollFd_, EPOLL_CTL_DEL, fd, &ev);
}
int Epoller::Wait(int timeoutMs) {
return epoll_wait(epollFd_, &events_[0], static_cast<int>(events_.size()), timeoutMs);
}
int Epoller::GetEventFd(size_t i) const {
assert(i < events_.size() && i >= 0);
return events_[i].data.fd;
}
uint32_t Epoller::GetEvents(size_t i) const {
assert(i < events_.size() && i >= 0);
return events_[i].events;
}
测试代码 --服务端
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include "../epoll/epoller.h"
int setNonblock(int fd){
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option|O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
int main()
{
printf("server start!\n");
int listenFd = socket(AF_INET, SOCK_STREAM,0);
if(listenFd == -1){
perror("create socket filed");
exit(1);
}
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(10000);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
int opt = 1;
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
int ret = -1;
ret = bind(listenFd, (struct sockaddr*) &serverAddr, sizeof(serverAddr));
if(ret == -1){
perror("bind socker error");
exit(1);
}
ret = listen(listenFd, 64);
if(ret == -1){
perror("listen socker error");
exit(1);
}
Epoller epoller;
epoller.AddFd(listenFd, EPOLLIN);
while(1)
{
int num = epoller.Wait();
for(int i=0; i<num; i++)
{
int curFd = epoller.GetEventFd(i);
if(curFd == listenFd)
{
int tempFd = accept(curFd, NULL, NULL);
printf("连接事件就绪,新的Fd:%d\n", tempFd);
setNonblock(tempFd);
bool flag = epoller.AddFd(tempFd, (EPOLL_EVENTS)(EPOLLET|EPOLLIN));
if(flag == false) {
printf("可能连接达到上限了,拒绝连接\n");
break;
}
}
else
{
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
while(1)
{
int len = recv(curFd, buffer, sizeof(buffer), 0);
if(len == 0)
{
epoller.DelFd(curFd);
break;
}
else if(len>0)
{
send(curFd, buffer, len, 0);
}
else
{
if(errno == EAGAIN)
{
break;
}
else
{
perror("recv error!");
exit(1);
}
}
}
}
}
}
return 0;
}
测试代码 --客户端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
void *working(void *arg)
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
printf("子线程:%ld, error in create socket\n",pthread_self());
pthread_exit(NULL);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(10000);
inet_pton(AF_INET,"127.0.0.1",&addr.sin_addr.s_addr);
int ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret == -1)
{
printf("子线程:%ld, error in connect socket\n",pthread_self());
pthread_exit(NULL);
}
int cnt = 0;
char buffer[1024];
while (cnt<=100)
{
sprintf(buffer, "子线程:%ld, 当前消息计数器为cnt:%d\n",pthread_self(),cnt);
write(fd, buffer, strlen(buffer) + 1);
memset(buffer, 0, sizeof(buffer));
int len = read(fd, buffer, sizeof(buffer));
if(len>0){
printf("子线程:%ld, 服务器消息:%s\n",pthread_self(), buffer);
}
else if(len == 0)
{
printf("子线程:%ld, 无消息,断开连接:%s\n",pthread_self(), buffer);
}
else{
printf("子线程:%ld, error in read socket\n",pthread_self());
pthread_exit(NULL);
}
sleep(1);
cnt++;
}
close(fd);
}
int main()
{
int n = 3;
for(int i=0; i<n; i++)
{
pthread_t tid;
pthread_create(&tid, NULL, working, NULL);
pthread_detach(tid);
}
pthread_exit(NULL);
return 0;
}
引用
- 源代码:https://github.com/Aged-cat/WebServer