小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系统编程专栏<—请点击 linux网络编程专栏<—请点击 倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己! 
目录
-
- 前言
- 一、前置知识
- 二、nocopy
- 三、Epoller
- 四、Main.cc
- 五、EpollServer.hpp
- 六、源代码
-
- Epoller.hpp
- EpollServer.hpp
- Log.hpp
- Main.cc
- makefile
- nocopy.hpp
- Socket.hpp
- 总结
前言
【linux】高级IO,I/O多路转接之epoll,接口和原理讲解,epoll_create,epoll_wait,epoll_ctl——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习 本文由小编为大家介绍——【linux】高级IO,I/O多路转接多路转接之epoll,epoll版本的TCP服务器的实现
一、前置知识

二、nocopy
#pragma once
class nocopy
{
public:
nocopy(){};
nocopy(const nocopy& ) = delete;
const nocopy& operator=(const nocopy& ) = delete;
};
#include "Epoller.hpp"
class Epoller : public nocopy
{};
int main()
{
Epoller ep;
Epoller ep1 = ep;
return 0;
}
运行结果如下 
三、Epoller

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/epoll.h>
#include "Log.hpp"
#include "nocopy.hpp"
class Epoller : public nocopy
{
static const int size = 128;
public:
Epoller()
{
_epfd = epoll_create(size);
if(_epfd == –1)
{
lg(Error, "epoll_create error: %s", strerror(errno));
}
else
{
lg(Info, "epoller_create success, epfd: %d", _epfd);
}
}
~Epoller()
{
if(_epfd > 0)
{
close(_epfd);
}
}
private:
int _epfd;
int _timeout{3000};
};

int EpollerWait(struct epoll_event revents[], int num)
{
int n = epoll_wait(_epfd, revents, num, _timeout);
return n;
}



int EpollerUpdate(int oper, int sock, uint32_t event)
{
int n = 0;
if(oper == EPOLL_CTL_DEL)
{
n = epoll_ctl(_epfd, oper, sock, nullptr);
if(n == –1)
{
lg(Error, "epoll_ctl delete error");
}
}
else
{
// EPOLL_CTL_ADD || EPOLL_CTL_MOD
struct epoll_event ev;
ev.data.fd = sock;
ev.events = event;
n = epoll_ctl(_epfd, oper, sock, &ev);
if(n == –1)
{
lg(Error, "epoll_ctl error");
}
}
return n;
}
四、Main.cc
#include "EpollServer.hpp"
#include <memory>
int main()
{
std::unique_ptr<EpollServer> epoll_svr(new EpollServer(8080));
epoll_svr->Init();
epoll_svr->Start();
return 0;
}
五、EpollServer.hpp
#include <iostream>
#include <memory>
#include "Log.hpp"
#include "Socket.hpp"
#include "nocopy.hpp"
#include "Epoller.hpp"
uint32_t EVENT_IN = (EPOLLIN);
uint32_t EVENT_OUT = (EPOLLOUT);
class EpollServer : public nocopy
{
static const int num = 64;
public:
EpollServer(uint16_t port)
:_listensock_ptr(new Sock())
,_epoller_ptr(new Epoller())
,_port(port)
{}
void Init()
{}
void Start()
{}
~EpollServer()
{
_listensock_ptr->Close();
}
private:
std::shared_ptr<Sock> _listensock_ptr;
std::shared_ptr<Epoller> _epoller_ptr;
uint16_t _port;
};
void Init()
{
_listensock_ptr->Socket();
_listensock_ptr->Bind(_port);
_listensock_ptr->Listen();
lg(Info, "create listen socket success, fd: %d", _listensock_ptr->Fd());
}
void Dispatcher(epoll_event revs[], int n)
{
}
void Start()
{
_epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, _listensock_ptr->Fd(), EVENT_IN);
struct epoll_event revs[num];
for(;;)
{
int n = _epoller_ptr->EpollerWait(revs, num);
if(n > 0)
{
lg(Debug, "event happened, fd: %d", revs[0].data.fd);
Dispatcher(revs, n);
}
else if(n == 0)
{
lg(Info, "time out…");
}
else
{
lg(Error, "epoll wait error");
}
}
}

void Accepter()
{
}
void Recver(int fd)
{
}
void Dispatcher(struct epoll_event revs[], int n)
{
for(int i = 0; i < n; i++)
{
int fd = revs[i].data.fd;
uint32_t event = revs[i].events;
if(event & EVENT_IN)
{
if(fd == _listensock_ptr->Fd())
{
Accepter();
}
else
{
Recver(fd);
}
}
else if(event & EVENT_OUT)
{
}
else
{
}
}
}
void Accepter()
{
std::string clientip;
uint16_t clientport;
int sock = _listensock_ptr->Accept(&clientip, &clientport);
if(sock > 0)
{
_epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, sock, EVENT_IN);
lg(Info, "get a new link, client info@ %s:%d", clientip.c_str(), clientport);
}
}
运行结果如下 
int EpollerWait(struct epoll_event revents[], int num)
{
// int n = epoll_wait(_epfd, revents, num, _timeout);
int n = epoll_wait(_epfd, revents, num, 0);
return n;
}
运行结果如下,非阻塞情况下一瞬间超时日志就会将屏幕打满 
int EpollerWait(struct epoll_event revents[], int num)
{
// int n = epoll_wait(_epfd, revents, num, _timeout);
// int n = epoll_wait(_epfd, revents, num, 0);
int n = epoll_wait(_epfd, revents, num, –1);
return n;
}
运行结果如下 
void Recver(int fd)
{
char buffer[1024];
ssize_t n = read(fd, buffer, sizeof(buffer) – 1);
if(n > 0)
{
buffer[n] = 0;
std::cout << "get a message: " << buffer << std::endl;
std::string echo_str = "server echo$ ";
echo_str += buffer;
write(fd, echo_str.c_str(), echo_str.size());
}
else if(n == 0)
{
lg(Info, "client quit, me to, close fd: %d", fd);
_epoller_ptr->EpollerUpdate(EPOLL_CTL_DEL, fd, 0);
close(fd);
}
else
{
lg(Warning, "recv error, fd: %d", fd);
_epoller_ptr->EpollerUpdate(EPOLL_CTL_DEL, fd, 0);
close(fd);
}
}
运行结果如下 
六、源代码
Epoller.hpp
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/epoll.h>
#include "Log.hpp"
#include "nocopy.hpp"
class Epoller : public nocopy
{
static const int size = 128;
public:
Epoller()
{
_epfd = epoll_create(size);
if(_epfd == –1)
{
lg(Error, "epoll_create error: %s", strerror(errno));
}
else
{
lg(Info, "epoller_create success, epfd: %d", _epfd);
}
}
int EpollerWait(struct epoll_event revents[], int num)
{
// int n = epoll_wait(_epfd, revents, num, _timeout);
// int n = epoll_wait(_epfd, revents, num, 0);
int n = epoll_wait(_epfd, revents, num, –1);
return n;
}
int EpollerUpdate(int oper, int sock, uint32_t event)
{
int n = 0;
if(oper == EPOLL_CTL_DEL)
{
n = epoll_ctl(_epfd, oper, sock, nullptr);
if(n == –1)
{
lg(Error, "epoll_ctl delete error");
}
}
else
{
// EPOLL_CTL_ADD || EPOLL_CTL_MOD
struct epoll_event ev;
ev.data.fd = sock;
ev.events = event;
n = epoll_ctl(_epfd, oper, sock, &ev);
if(n == –1)
{
lg(Error, "epoll_ctl error");
}
}
return n;
}
~Epoller()
{
if(_epfd >= 0)
{
close(_epfd);
}
}
private:
int _epfd;
int _timeout{3000};
};
EpollServer.hpp
#include <iostream>
#include <memory>
#include <string>
#include <unistd.h>
#include "Log.hpp"
#include "Socket.hpp"
#include "nocopy.hpp"
#include "Epoller.hpp"
uint32_t EVENT_IN = (EPOLLIN);
uint32_t EVENT_OUT = (EPOLLOUT);
class EpollServer : public nocopy
{
static const int num = 64;
public:
EpollServer(uint16_t port)
:_listensock_ptr(new Sock())
,_epoller_ptr(new Epoller())
,_port(port)
{}
void Init()
{
_listensock_ptr->Socket();
_listensock_ptr->Bind(_port);
_listensock_ptr->Listen();
lg(Info, "create listen socket success, fd: %d", _listensock_ptr->Fd());
}
void Accepter()
{
std::string clientip;
uint16_t clientport;
int sock = _listensock_ptr->Accept(&clientip, &clientport);
if(sock > 0)
{
_epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, sock, EVENT_IN);
lg(Info, "get a new link, client info@ %s:%d", clientip.c_str(), clientport);
}
}
void Recver(int fd)
{
char buffer[1024];
ssize_t n = read(fd, buffer, sizeof(buffer) – 1);
if(n > 0)
{
buffer[n] = 0;
std::cout << "get a message: " << buffer << std::endl;
std::string echo_str = "server echo$ ";
echo_str += buffer;
write(fd, echo_str.c_str(), echo_str.size());
}
else if(n == 0)
{
lg(Info, "client quit, me to, close fd: %d", fd);
_epoller_ptr->EpollerUpdate(EPOLL_CTL_DEL, fd, 0);
close(fd);
}
else
{
lg(Warning, "recv error, fd: %d", fd);
_epoller_ptr->EpollerUpdate(EPOLL_CTL_DEL, fd, 0);
close(fd);
}
}
void Dispatcher(struct epoll_event revs[], int n)
{
for(int i = 0; i < n; i++)
{
int fd = revs[i].data.fd;
uint32_t event = revs[i].events;
if(event & EVENT_IN)
{
if(fd == _listensock_ptr->Fd())
{
Accepter();
}
else
{
Recver(fd);
}
}
else if(event & EVENT_OUT)
{
}
else
{
}
}
}
void Start()
{
_epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, _listensock_ptr->Fd(), EVENT_IN);
struct epoll_event revs[num];
for(;;)
{
int n = _epoller_ptr->EpollerWait(revs, num);
if(n > 0)
{
lg(Debug, "event happened, fd: %d", revs[0].data.fd);
Dispatcher(revs, n);
}
else if(n == 0)
{
lg(Info, "time out…");
}
else
{
lg(Error, "epoll wait error");
}
}
}
~EpollServer()
{
_listensock_ptr->Close();
}
private:
std::shared_ptr<Sock> _listensock_ptr;
std::shared_ptr<Epoller> _epoller_ptr;
uint16_t _port;
};
Log.hpp
#pragma once
#include <iostream>
#include <string>
#include <ctime>
#include <cstdio>
#include <cstdarg>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE 1024
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4
#define Screen 1 //输出到屏幕上
#define Onefile 2 //输出到一个文件中
#define Classfile 3 //根据事件等级输出到不同的文件中
#define LogFile "log.txt" //日志名称
class Log
{
public:
Log()
{
printMethod = Screen;
path = "./log/";
}
void Enable(int method) //改变日志打印方式
{
printMethod = method;
}
~Log()
{}
std::string levelToString(int level)
{
switch(level)
{
case Info:
return "Info";
case Debug:
return "Debug";
case Warning:
return "Warning";
case Error:
return "Error";
case Fatal:
return "Fatal";
default:
return "";
}
}
void operator()(int level, const char* format, ...)
{
//默认部分 = 日志等级 + 日志时间
time_t t = time(nullptr);
struct tm* ctime = localtime(&t);
char leftbuffer[SIZE];
snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
ctime->tm_hour, ctime->tm_min, ctime->tm_sec);
va_list s;
va_start(s, format);
char rightbuffer[SIZE];
vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
va_end(s);
char logtxt[2 * SIZE];
snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);
printLog(level, logtxt);
}
void printLog(int level, const std::string& logtxt)
{
switch(printMethod)
{
case Screen:
std::cout << logtxt << std::endl;
break;
case Onefile:
printOneFile(LogFile, logtxt);
break;
case Classfile:
printClassFile(level, logtxt);
break;
default:
break;
}
}
void printOneFile(const std::string& logname, const std::string& logtxt)
{
std::string _logname = path + logname;
int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
if(fd < 0)
return;
write(fd, logtxt.c_str(), logtxt.size());
close(fd);
}
void printClassFile(int level, const std::string& logtxt)
{
std::string filename = LogFile;
filename += ".";
filename += levelToString(level);
printOneFile(filename, logtxt);
}
private:
int printMethod;
std::string path;
};
Log lg;
Main.cc
#include "EpollServer.hpp"
#include <memory>
int main()
{
std::unique_ptr<EpollServer> epoll_svr(new EpollServer(8080));
epoll_svr->Init();
epoll_svr->Start();
// Epoller ep;
// Epoller ep1 = ep;
return 0;
}
makefile
epoll_server:Main.cc
g++ –o $@ $^ –std=c++11
.PHONY:clean
clean:
rm –f epoll_server
nocopy.hpp
#pragma once
class nocopy
{
public:
nocopy(){};
nocopy(const nocopy& ) = delete;
const nocopy& operator=(const nocopy& ) = delete;
};
Socket.hpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
const int backlog = 10;
enum{
SocketErr = 1,
BindErr,
ListenErr,
};
class Sock
{
public:
Sock()
{}
void Socket()
{
sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd_ < 0)
{
lg(Fatal, "socket error, %s : %d", strerror(errno), errno);
exit(SocketErr);
}
int opt = 1;
setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
}
void Bind(uint16_t port)
{
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
socklen_t len = sizeof(local);
if(bind(sockfd_, (struct sockaddr*)&local, len) < 0)
{
lg(Fatal, "bind error, %s : %d", strerror(errno), errno);
exit(BindErr);
}
}
void Listen()
{
if(listen(sockfd_, backlog) < 0)
{
lg(Fatal, "listen error, %s : %d", strerror(errno), errno);
exit(ListenErr);
}
}
int Accept(std::string* clientip, uint16_t* clientport)
{
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int newfd = accept(sockfd_, (struct sockaddr*)&peer, &len);
if(newfd < 0)
{
lg(Warning, "accept error, %s : %d", strerror(errno), errno);
return –1;
}
char ipstr[128];
inet_ntop(AF_INET, &(peer.sin_addr), ipstr, sizeof(ipstr));
*clientip = ipstr;
*clientport = ntohs(peer.sin_port);
return newfd;
}
bool Connect(const std::string& serverip, uint16_t serverport)
{
struct sockaddr_in peer;
memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_port = htons(serverport);
inet_pton(AF_INET, serverip.c_str(), &(peer.sin_addr));
socklen_t len = sizeof(peer);
int n = connect(sockfd_, (struct sockaddr*)&peer, len);
if(n == –1)
{
std::cerr << "connect to " << serverip << ':' << serverport << "error" << std::endl;
return false;
}
return true;
}
void Close()
{
if(sockfd_ > 0)
{
close(sockfd_);
}
}
int Fd()
{
return sockfd_;
}
~Sock()
{}
private:
int sockfd_;
};
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助 水滴石穿,坚持就是胜利,读者朋友们可以点个关注 点赞收藏加关注,找到小编不迷路!
网硕互联帮助中心







评论前必须登录!
注册